emdash 0.0.0-b → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (661) hide show
  1. package/README.md +87 -43
  2. package/dist/adapters-BLMa4JGD.d.mts +106 -0
  3. package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
  4. package/dist/apply-Bjfq_b4-.mjs +1293 -0
  5. package/dist/apply-Bjfq_b4-.mjs.map +1 -0
  6. package/dist/astro/index.d.mts +51 -0
  7. package/dist/astro/index.d.mts.map +1 -0
  8. package/dist/astro/index.mjs +1336 -0
  9. package/dist/astro/index.mjs.map +1 -0
  10. package/dist/astro/middleware/auth.d.mts +31 -0
  11. package/dist/astro/middleware/auth.d.mts.map +1 -0
  12. package/dist/astro/middleware/auth.mjs +654 -0
  13. package/dist/astro/middleware/auth.mjs.map +1 -0
  14. package/dist/astro/middleware/redirect.d.mts +22 -0
  15. package/dist/astro/middleware/redirect.d.mts.map +1 -0
  16. package/dist/astro/middleware/redirect.mjs +63 -0
  17. package/dist/astro/middleware/redirect.mjs.map +1 -0
  18. package/dist/astro/middleware/request-context.d.mts +18 -0
  19. package/dist/astro/middleware/request-context.d.mts.map +1 -0
  20. package/dist/astro/middleware/request-context.mjs +1310 -0
  21. package/dist/astro/middleware/request-context.mjs.map +1 -0
  22. package/dist/astro/middleware/setup.d.mts +20 -0
  23. package/dist/astro/middleware/setup.d.mts.map +1 -0
  24. package/dist/astro/middleware/setup.mjs +47 -0
  25. package/dist/astro/middleware/setup.mjs.map +1 -0
  26. package/dist/astro/middleware.d.mts +13 -0
  27. package/dist/astro/middleware.d.mts.map +1 -0
  28. package/dist/astro/middleware.mjs +1613 -0
  29. package/dist/astro/middleware.mjs.map +1 -0
  30. package/dist/astro/types.d.mts +250 -0
  31. package/dist/astro/types.d.mts.map +1 -0
  32. package/dist/astro/types.mjs +1 -0
  33. package/dist/base64-MBPo9ozB.mjs +59 -0
  34. package/dist/base64-MBPo9ozB.mjs.map +1 -0
  35. package/dist/byline-CL847F26.mjs +213 -0
  36. package/dist/byline-CL847F26.mjs.map +1 -0
  37. package/dist/bylines-C2a-2TGt.mjs +136 -0
  38. package/dist/bylines-C2a-2TGt.mjs.map +1 -0
  39. package/dist/chunk-ClPoSABd.mjs +21 -0
  40. package/dist/cli/index.d.mts +1 -0
  41. package/dist/cli/index.mjs +3909 -0
  42. package/dist/cli/index.mjs.map +1 -0
  43. package/dist/client/cf-access.d.mts +60 -0
  44. package/dist/client/cf-access.d.mts.map +1 -0
  45. package/dist/client/cf-access.mjs +179 -0
  46. package/dist/client/cf-access.mjs.map +1 -0
  47. package/dist/client/index.d.mts +398 -0
  48. package/dist/client/index.d.mts.map +1 -0
  49. package/dist/client/index.mjs +346 -0
  50. package/dist/client/index.mjs.map +1 -0
  51. package/dist/config-CKE8p9xM.mjs +55 -0
  52. package/dist/config-CKE8p9xM.mjs.map +1 -0
  53. package/dist/connection-B4zVnQIa.mjs +40 -0
  54. package/dist/connection-B4zVnQIa.mjs.map +1 -0
  55. package/dist/content-D6C2WsZC.mjs +824 -0
  56. package/dist/content-D6C2WsZC.mjs.map +1 -0
  57. package/dist/db/index.d.mts +4 -0
  58. package/dist/db/index.mjs +62 -0
  59. package/dist/db/index.mjs.map +1 -0
  60. package/dist/db/libsql.d.mts +11 -0
  61. package/dist/db/libsql.d.mts.map +1 -0
  62. package/dist/db/libsql.mjs +17 -0
  63. package/dist/db/libsql.mjs.map +1 -0
  64. package/dist/db/postgres.d.mts +11 -0
  65. package/dist/db/postgres.d.mts.map +1 -0
  66. package/dist/db/postgres.mjs +30 -0
  67. package/dist/db/postgres.mjs.map +1 -0
  68. package/dist/db/sqlite.d.mts +11 -0
  69. package/dist/db/sqlite.d.mts.map +1 -0
  70. package/dist/db/sqlite.mjs +16 -0
  71. package/dist/db/sqlite.mjs.map +1 -0
  72. package/dist/default-Cyi4aAxu.mjs +81 -0
  73. package/dist/default-Cyi4aAxu.mjs.map +1 -0
  74. package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
  75. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
  76. package/dist/error-Cxz0tQeO.mjs +27 -0
  77. package/dist/error-Cxz0tQeO.mjs.map +1 -0
  78. package/dist/index-C1xF3OGh.d.mts +4527 -0
  79. package/dist/index-C1xF3OGh.d.mts.map +1 -0
  80. package/dist/index.d.mts +16 -0
  81. package/dist/index.mjs +30 -0
  82. package/dist/load-yOOlckBj.mjs +28 -0
  83. package/dist/load-yOOlckBj.mjs.map +1 -0
  84. package/dist/loader-fz8Q_3EO.mjs +447 -0
  85. package/dist/loader-fz8Q_3EO.mjs.map +1 -0
  86. package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
  87. package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
  88. package/dist/media/index.d.mts +26 -0
  89. package/dist/media/index.d.mts.map +1 -0
  90. package/dist/media/index.mjs +55 -0
  91. package/dist/media/index.mjs.map +1 -0
  92. package/dist/media/local-runtime.d.mts +39 -0
  93. package/dist/media/local-runtime.d.mts.map +1 -0
  94. package/dist/media/local-runtime.mjs +133 -0
  95. package/dist/media/local-runtime.mjs.map +1 -0
  96. package/dist/media-DqHVh136.mjs +200 -0
  97. package/dist/media-DqHVh136.mjs.map +1 -0
  98. package/dist/mode-C2EzN1uE.mjs +23 -0
  99. package/dist/mode-C2EzN1uE.mjs.map +1 -0
  100. package/dist/page/index.d.mts +140 -0
  101. package/dist/page/index.d.mts.map +1 -0
  102. package/dist/page/index.mjs +416 -0
  103. package/dist/page/index.mjs.map +1 -0
  104. package/dist/placeholder-CmGAmqeO.d.mts +276 -0
  105. package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
  106. package/dist/placeholder-SmpOx-_v.mjs +243 -0
  107. package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
  108. package/dist/plugin-utils.d.mts +58 -0
  109. package/dist/plugin-utils.d.mts.map +1 -0
  110. package/dist/plugin-utils.mjs +78 -0
  111. package/dist/plugin-utils.mjs.map +1 -0
  112. package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
  113. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
  114. package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
  115. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
  116. package/dist/query-CS_iSj34.mjs +460 -0
  117. package/dist/query-CS_iSj34.mjs.map +1 -0
  118. package/dist/redirect-DIfIni3r.mjs +329 -0
  119. package/dist/redirect-DIfIni3r.mjs.map +1 -0
  120. package/dist/registry-D_w5HW4G.mjs +863 -0
  121. package/dist/registry-D_w5HW4G.mjs.map +1 -0
  122. package/dist/request-context.d.mts +49 -0
  123. package/dist/request-context.d.mts.map +1 -0
  124. package/dist/request-context.mjs +43 -0
  125. package/dist/request-context.mjs.map +1 -0
  126. package/dist/runner-C0hCbYnD.mjs +1412 -0
  127. package/dist/runner-C0hCbYnD.mjs.map +1 -0
  128. package/dist/runner-EAtf0ZIe.d.mts +27 -0
  129. package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
  130. package/dist/runtime.d.mts +26 -0
  131. package/dist/runtime.d.mts.map +1 -0
  132. package/dist/runtime.mjs +42 -0
  133. package/dist/runtime.mjs.map +1 -0
  134. package/dist/search-DG603UrT.mjs +9211 -0
  135. package/dist/search-DG603UrT.mjs.map +1 -0
  136. package/dist/seed/index.d.mts +3 -0
  137. package/dist/seed/index.mjs +15 -0
  138. package/dist/seo/index.d.mts +70 -0
  139. package/dist/seo/index.d.mts.map +1 -0
  140. package/dist/seo/index.mjs +70 -0
  141. package/dist/seo/index.mjs.map +1 -0
  142. package/dist/storage/local.d.mts +39 -0
  143. package/dist/storage/local.d.mts.map +1 -0
  144. package/dist/storage/local.mjs +166 -0
  145. package/dist/storage/local.mjs.map +1 -0
  146. package/dist/storage/s3.d.mts +32 -0
  147. package/dist/storage/s3.d.mts.map +1 -0
  148. package/dist/storage/s3.mjs +175 -0
  149. package/dist/storage/s3.mjs.map +1 -0
  150. package/dist/tokens-DpgrkrXK.mjs +171 -0
  151. package/dist/tokens-DpgrkrXK.mjs.map +1 -0
  152. package/dist/transport-BFGblqwG.d.mts +42 -0
  153. package/dist/transport-BFGblqwG.d.mts.map +1 -0
  154. package/dist/transport-yxiQsi8I.mjs +418 -0
  155. package/dist/transport-yxiQsi8I.mjs.map +1 -0
  156. package/dist/types-BRuPJGdV.d.mts +102 -0
  157. package/dist/types-BRuPJGdV.d.mts.map +1 -0
  158. package/dist/types-C4-fAxN3.d.mts +182 -0
  159. package/dist/types-C4-fAxN3.d.mts.map +1 -0
  160. package/dist/types-CMMN0pNg.mjs +31 -0
  161. package/dist/types-CMMN0pNg.mjs.map +1 -0
  162. package/dist/types-CUBbjgmP.mjs +16 -0
  163. package/dist/types-CUBbjgmP.mjs.map +1 -0
  164. package/dist/types-DRjfYOEv.d.mts +426 -0
  165. package/dist/types-DRjfYOEv.d.mts.map +1 -0
  166. package/dist/types-DY5zk5HN.mjs +73 -0
  167. package/dist/types-DY5zk5HN.mjs.map +1 -0
  168. package/dist/types-DaNLHo_T.d.mts +184 -0
  169. package/dist/types-DaNLHo_T.d.mts.map +1 -0
  170. package/dist/types-DvhsUmSJ.d.mts +1111 -0
  171. package/dist/types-DvhsUmSJ.d.mts.map +1 -0
  172. package/dist/validate-CpBtVMsD.d.mts +378 -0
  173. package/dist/validate-CpBtVMsD.d.mts.map +1 -0
  174. package/dist/validate-CqRJb_xU.mjs +97 -0
  175. package/dist/validate-CqRJb_xU.mjs.map +1 -0
  176. package/dist/validate-O7PWmlnq.mjs +328 -0
  177. package/dist/validate-O7PWmlnq.mjs.map +1 -0
  178. package/locals.d.ts +46 -0
  179. package/package.json +233 -19
  180. package/src/api/authorize.ts +63 -0
  181. package/src/api/csrf.ts +48 -0
  182. package/src/api/error.ts +99 -0
  183. package/src/api/errors.ts +445 -0
  184. package/src/api/escape.ts +9 -0
  185. package/src/api/handlers/api-tokens.ts +240 -0
  186. package/src/api/handlers/comments.ts +314 -0
  187. package/src/api/handlers/content.ts +1315 -0
  188. package/src/api/handlers/dashboard.ts +205 -0
  189. package/src/api/handlers/device-flow.ts +684 -0
  190. package/src/api/handlers/index.ts +163 -0
  191. package/src/api/handlers/manifest.ts +158 -0
  192. package/src/api/handlers/marketplace.ts +930 -0
  193. package/src/api/handlers/media.ts +207 -0
  194. package/src/api/handlers/menus.ts +493 -0
  195. package/src/api/handlers/oauth-authorization.ts +429 -0
  196. package/src/api/handlers/oauth-clients.ts +349 -0
  197. package/src/api/handlers/oauth-user-lookup.ts +39 -0
  198. package/src/api/handlers/plugins.ts +254 -0
  199. package/src/api/handlers/redirects.ts +360 -0
  200. package/src/api/handlers/revision.ts +145 -0
  201. package/src/api/handlers/schema.ts +534 -0
  202. package/src/api/handlers/sections.ts +289 -0
  203. package/src/api/handlers/seo.ts +115 -0
  204. package/src/api/handlers/settings.ts +49 -0
  205. package/src/api/handlers/snapshot.ts +350 -0
  206. package/src/api/handlers/taxonomies.ts +523 -0
  207. package/src/api/index.ts +6 -0
  208. package/src/api/openapi/document.ts +2368 -0
  209. package/src/api/openapi/index.ts +1 -0
  210. package/src/api/parse.ts +139 -0
  211. package/src/api/redirect.ts +14 -0
  212. package/src/api/rev.ts +67 -0
  213. package/src/api/schemas/auth.ts +112 -0
  214. package/src/api/schemas/bylines.ts +85 -0
  215. package/src/api/schemas/comments.ts +117 -0
  216. package/src/api/schemas/common.ts +89 -0
  217. package/src/api/schemas/content.ts +191 -0
  218. package/src/api/schemas/import.ts +52 -0
  219. package/src/api/schemas/index.ts +17 -0
  220. package/src/api/schemas/media.ts +116 -0
  221. package/src/api/schemas/menus.ts +111 -0
  222. package/src/api/schemas/redirects.ts +155 -0
  223. package/src/api/schemas/schema.ts +203 -0
  224. package/src/api/schemas/search.ts +63 -0
  225. package/src/api/schemas/sections.ts +67 -0
  226. package/src/api/schemas/settings.ts +63 -0
  227. package/src/api/schemas/setup.ts +37 -0
  228. package/src/api/schemas/taxonomies.ts +113 -0
  229. package/src/api/schemas/users.ts +96 -0
  230. package/src/api/schemas/widgets.ts +80 -0
  231. package/src/api/site-url.ts +25 -0
  232. package/src/api/types.ts +82 -0
  233. package/src/astro/index.ts +27 -0
  234. package/src/astro/integration/index.ts +303 -0
  235. package/src/astro/integration/routes.ts +834 -0
  236. package/src/astro/integration/runtime.ts +338 -0
  237. package/src/astro/integration/virtual-modules.ts +469 -0
  238. package/src/astro/integration/vite-config.ts +335 -0
  239. package/src/astro/middleware/auth.ts +743 -0
  240. package/src/astro/middleware/redirect.ts +89 -0
  241. package/src/astro/middleware/request-context.ts +129 -0
  242. package/src/astro/middleware/setup.ts +89 -0
  243. package/src/astro/middleware.ts +398 -0
  244. package/src/astro/routes/PluginRegistry.tsx +15 -0
  245. package/src/astro/routes/admin.astro +81 -0
  246. package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
  247. package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
  248. package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
  249. package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
  250. package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
  251. package/src/astro/routes/api/admin/bylines/index.ts +72 -0
  252. package/src/astro/routes/api/admin/comments/[id]/status.ts +116 -0
  253. package/src/astro/routes/api/admin/comments/[id].ts +64 -0
  254. package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
  255. package/src/astro/routes/api/admin/comments/counts.ts +30 -0
  256. package/src/astro/routes/api/admin/comments/index.ts +46 -0
  257. package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
  258. package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
  259. package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
  260. package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
  261. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
  262. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
  263. package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
  264. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
  265. package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
  266. package/src/astro/routes/api/admin/plugins/index.ts +32 -0
  267. package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
  268. package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
  269. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
  270. package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
  271. package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
  272. package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
  273. package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
  274. package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
  275. package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
  276. package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
  277. package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
  278. package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
  279. package/src/astro/routes/api/admin/users/index.ts +66 -0
  280. package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
  281. package/src/astro/routes/api/auth/invite/accept.ts +52 -0
  282. package/src/astro/routes/api/auth/invite/complete.ts +84 -0
  283. package/src/astro/routes/api/auth/invite/index.ts +99 -0
  284. package/src/astro/routes/api/auth/logout.ts +40 -0
  285. package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
  286. package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
  287. package/src/astro/routes/api/auth/me.ts +60 -0
  288. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
  289. package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
  290. package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
  291. package/src/astro/routes/api/auth/passkey/index.ts +54 -0
  292. package/src/astro/routes/api/auth/passkey/options.ts +82 -0
  293. package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
  294. package/src/astro/routes/api/auth/passkey/register/verify.ts +115 -0
  295. package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
  296. package/src/astro/routes/api/auth/signup/complete.ts +85 -0
  297. package/src/astro/routes/api/auth/signup/request.ts +77 -0
  298. package/src/astro/routes/api/auth/signup/verify.ts +53 -0
  299. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
  300. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
  301. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
  302. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
  303. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
  304. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
  305. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
  306. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
  307. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
  308. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +101 -0
  309. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
  310. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
  311. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
  312. package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
  313. package/src/astro/routes/api/content/[collection]/index.ts +59 -0
  314. package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
  315. package/src/astro/routes/api/dashboard.ts +32 -0
  316. package/src/astro/routes/api/dev/emails.ts +36 -0
  317. package/src/astro/routes/api/import/probe.ts +47 -0
  318. package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
  319. package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
  320. package/src/astro/routes/api/import/wordpress/media.ts +338 -0
  321. package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
  322. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
  323. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
  324. package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
  325. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
  326. package/src/astro/routes/api/manifest.ts +62 -0
  327. package/src/astro/routes/api/mcp.ts +124 -0
  328. package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
  329. package/src/astro/routes/api/media/[id].ts +145 -0
  330. package/src/astro/routes/api/media/file/[key].ts +79 -0
  331. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
  332. package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
  333. package/src/astro/routes/api/media/providers/index.ts +30 -0
  334. package/src/astro/routes/api/media/upload-url.ts +137 -0
  335. package/src/astro/routes/api/media.ts +190 -0
  336. package/src/astro/routes/api/menus/[name]/items.ts +87 -0
  337. package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
  338. package/src/astro/routes/api/menus/[name].ts +65 -0
  339. package/src/astro/routes/api/menus/index.ts +47 -0
  340. package/src/astro/routes/api/oauth/authorize.ts +412 -0
  341. package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
  342. package/src/astro/routes/api/oauth/device/code.ts +51 -0
  343. package/src/astro/routes/api/oauth/device/token.ts +69 -0
  344. package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
  345. package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
  346. package/src/astro/routes/api/oauth/token.ts +184 -0
  347. package/src/astro/routes/api/openapi.json.ts +32 -0
  348. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
  349. package/src/astro/routes/api/redirects/404s/index.ts +72 -0
  350. package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
  351. package/src/astro/routes/api/redirects/[id].ts +84 -0
  352. package/src/astro/routes/api/redirects/index.ts +52 -0
  353. package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
  354. package/src/astro/routes/api/revisions/[revisionId]/restore.ts +58 -0
  355. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
  356. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
  357. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
  358. package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
  359. package/src/astro/routes/api/schema/collections/index.ts +47 -0
  360. package/src/astro/routes/api/schema/index.ts +109 -0
  361. package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
  362. package/src/astro/routes/api/schema/orphans/index.ts +26 -0
  363. package/src/astro/routes/api/search/enable.ts +64 -0
  364. package/src/astro/routes/api/search/index.ts +55 -0
  365. package/src/astro/routes/api/search/rebuild.ts +72 -0
  366. package/src/astro/routes/api/search/stats.ts +35 -0
  367. package/src/astro/routes/api/search/suggest.ts +53 -0
  368. package/src/astro/routes/api/sections/[slug].ts +84 -0
  369. package/src/astro/routes/api/sections/index.ts +52 -0
  370. package/src/astro/routes/api/settings/email.ts +150 -0
  371. package/src/astro/routes/api/settings.ts +67 -0
  372. package/src/astro/routes/api/setup/admin-verify.ts +100 -0
  373. package/src/astro/routes/api/setup/admin.ts +94 -0
  374. package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
  375. package/src/astro/routes/api/setup/dev-reset.ts +40 -0
  376. package/src/astro/routes/api/setup/index.ts +126 -0
  377. package/src/astro/routes/api/setup/status.ts +122 -0
  378. package/src/astro/routes/api/snapshot.ts +75 -0
  379. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
  380. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
  381. package/src/astro/routes/api/taxonomies/index.ts +59 -0
  382. package/src/astro/routes/api/themes/preview.ts +77 -0
  383. package/src/astro/routes/api/typegen.ts +114 -0
  384. package/src/astro/routes/api/well-known/auth.ts +68 -0
  385. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
  386. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
  387. package/src/astro/routes/api/widget-areas/[name]/reorder.ts +68 -0
  388. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
  389. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
  390. package/src/astro/routes/api/widget-areas/[name].ts +87 -0
  391. package/src/astro/routes/api/widget-areas/index.ts +99 -0
  392. package/src/astro/routes/api/widget-components.ts +22 -0
  393. package/src/astro/routes/robots.txt.ts +77 -0
  394. package/src/astro/routes/sitemap.xml.ts +97 -0
  395. package/src/astro/storage/adapters.ts +74 -0
  396. package/src/astro/storage/index.ts +19 -0
  397. package/src/astro/storage/types.ts +60 -0
  398. package/src/astro/types.ts +346 -0
  399. package/src/auth/api-tokens.ts +25 -0
  400. package/src/auth/challenge-store.ts +80 -0
  401. package/src/auth/mode.ts +96 -0
  402. package/src/auth/oauth-state-store.ts +96 -0
  403. package/src/auth/passkey-config.ts +27 -0
  404. package/src/auth/rate-limit.ts +158 -0
  405. package/src/auth/scopes.ts +33 -0
  406. package/src/auth/types.ts +104 -0
  407. package/src/aws-sdk.d.ts +100 -0
  408. package/src/bylines/index.ts +237 -0
  409. package/src/cleanup.ts +153 -0
  410. package/src/cli/client-factory.ts +100 -0
  411. package/src/cli/commands/auth.ts +46 -0
  412. package/src/cli/commands/bundle-utils.ts +247 -0
  413. package/src/cli/commands/bundle.ts +609 -0
  414. package/src/cli/commands/content.ts +442 -0
  415. package/src/cli/commands/dev.ts +191 -0
  416. package/src/cli/commands/doctor.ts +211 -0
  417. package/src/cli/commands/export-seed.ts +630 -0
  418. package/src/cli/commands/import/wordpress.ts +1056 -0
  419. package/src/cli/commands/init.ts +192 -0
  420. package/src/cli/commands/login.ts +547 -0
  421. package/src/cli/commands/media.ts +165 -0
  422. package/src/cli/commands/menu.ts +67 -0
  423. package/src/cli/commands/plugin-init.ts +291 -0
  424. package/src/cli/commands/plugin-validate.ts +31 -0
  425. package/src/cli/commands/plugin.ts +33 -0
  426. package/src/cli/commands/publish.ts +697 -0
  427. package/src/cli/commands/schema.ts +233 -0
  428. package/src/cli/commands/search-cmd.ts +54 -0
  429. package/src/cli/commands/seed.ts +286 -0
  430. package/src/cli/commands/taxonomy.ts +128 -0
  431. package/src/cli/commands/types.ts +68 -0
  432. package/src/cli/credentials.ts +236 -0
  433. package/src/cli/index.ts +70 -0
  434. package/src/cli/output.ts +75 -0
  435. package/src/cli/wxr/parser.ts +969 -0
  436. package/src/client/cf-access.ts +193 -0
  437. package/src/client/index.ts +854 -0
  438. package/src/client/portable-text.ts +413 -0
  439. package/src/client/transport.ts +200 -0
  440. package/src/comments/moderator.ts +46 -0
  441. package/src/comments/notifications.ts +144 -0
  442. package/src/comments/query.ts +105 -0
  443. package/src/comments/service.ts +213 -0
  444. package/src/components/Break.astro +45 -0
  445. package/src/components/Button.astro +71 -0
  446. package/src/components/Buttons.astro +49 -0
  447. package/src/components/Code.astro +59 -0
  448. package/src/components/Columns.astro +59 -0
  449. package/src/components/CommentForm.astro +315 -0
  450. package/src/components/Comments.astro +232 -0
  451. package/src/components/Cover.astro +128 -0
  452. package/src/components/EmDashBodyEnd.astro +32 -0
  453. package/src/components/EmDashBodyStart.astro +32 -0
  454. package/src/components/EmDashHead.astro +53 -0
  455. package/src/components/EmDashImage.astro +178 -0
  456. package/src/components/EmDashMedia.astro +167 -0
  457. package/src/components/Embed.astro +128 -0
  458. package/src/components/File.astro +122 -0
  459. package/src/components/Gallery.astro +93 -0
  460. package/src/components/HtmlBlock.astro +33 -0
  461. package/src/components/Image.astro +178 -0
  462. package/src/components/InlineEditor.astro +27 -0
  463. package/src/components/InlinePortableTextEditor.tsx +1905 -0
  464. package/src/components/LiveSearch.astro +614 -0
  465. package/src/components/PortableText.astro +51 -0
  466. package/src/components/Pullquote.astro +51 -0
  467. package/src/components/Table.astro +108 -0
  468. package/src/components/WidgetArea.astro +22 -0
  469. package/src/components/WidgetRenderer.astro +72 -0
  470. package/src/components/index.ts +116 -0
  471. package/src/components/marks/Link.astro +31 -0
  472. package/src/components/marks/StrikeThrough.astro +7 -0
  473. package/src/components/marks/Subscript.astro +7 -0
  474. package/src/components/marks/Superscript.astro +7 -0
  475. package/src/components/marks/Underline.astro +7 -0
  476. package/src/components/widgets/Archives.astro +65 -0
  477. package/src/components/widgets/Categories.astro +35 -0
  478. package/src/components/widgets/RecentPosts.astro +51 -0
  479. package/src/components/widgets/Search.astro +18 -0
  480. package/src/components/widgets/Tags.astro +38 -0
  481. package/src/content/converters/index.ts +9 -0
  482. package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
  483. package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
  484. package/src/content/converters/types.ts +120 -0
  485. package/src/content/index.ts +5 -0
  486. package/src/database/connection.ts +67 -0
  487. package/src/database/dialect-helpers.ts +138 -0
  488. package/src/database/index.ts +5 -0
  489. package/src/database/migrations/001_initial.ts +170 -0
  490. package/src/database/migrations/002_media_status.ts +26 -0
  491. package/src/database/migrations/003_schema_registry.ts +79 -0
  492. package/src/database/migrations/004_plugins.ts +62 -0
  493. package/src/database/migrations/005_menus.ts +67 -0
  494. package/src/database/migrations/006_taxonomy_defs.ts +51 -0
  495. package/src/database/migrations/007_widgets.ts +42 -0
  496. package/src/database/migrations/008_auth.ts +194 -0
  497. package/src/database/migrations/009_user_disabled.ts +27 -0
  498. package/src/database/migrations/011_sections.ts +65 -0
  499. package/src/database/migrations/012_search.ts +25 -0
  500. package/src/database/migrations/013_scheduled_publishing.ts +51 -0
  501. package/src/database/migrations/014_draft_revisions.ts +72 -0
  502. package/src/database/migrations/015_indexes.ts +82 -0
  503. package/src/database/migrations/016_api_tokens.ts +89 -0
  504. package/src/database/migrations/017_authorization_codes.ts +45 -0
  505. package/src/database/migrations/018_seo.ts +56 -0
  506. package/src/database/migrations/019_i18n.ts +618 -0
  507. package/src/database/migrations/020_collection_url_pattern.ts +23 -0
  508. package/src/database/migrations/021_remove_section_categories.ts +43 -0
  509. package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
  510. package/src/database/migrations/023_plugin_metadata.ts +33 -0
  511. package/src/database/migrations/024_media_placeholders.ts +32 -0
  512. package/src/database/migrations/025_oauth_clients.ts +28 -0
  513. package/src/database/migrations/026_cron_tasks.ts +49 -0
  514. package/src/database/migrations/027_comments.ts +87 -0
  515. package/src/database/migrations/028_drop_author_url.ts +9 -0
  516. package/src/database/migrations/029_redirects.ts +67 -0
  517. package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
  518. package/src/database/migrations/031_bylines.ts +90 -0
  519. package/src/database/migrations/032_rate_limits.ts +39 -0
  520. package/src/database/migrations/runner.ts +170 -0
  521. package/src/database/repositories/audit.ts +294 -0
  522. package/src/database/repositories/byline.ts +387 -0
  523. package/src/database/repositories/comment.ts +458 -0
  524. package/src/database/repositories/content.ts +1144 -0
  525. package/src/database/repositories/index.ts +30 -0
  526. package/src/database/repositories/media.ts +347 -0
  527. package/src/database/repositories/options.ts +150 -0
  528. package/src/database/repositories/plugin-storage.ts +373 -0
  529. package/src/database/repositories/redirect.ts +480 -0
  530. package/src/database/repositories/revision.ts +200 -0
  531. package/src/database/repositories/seo.ts +176 -0
  532. package/src/database/repositories/taxonomy.ts +294 -0
  533. package/src/database/repositories/types.ts +132 -0
  534. package/src/database/repositories/user.ts +258 -0
  535. package/src/database/transaction.ts +54 -0
  536. package/src/database/types.ts +501 -0
  537. package/src/database/validate.ts +138 -0
  538. package/src/db/adapters.ts +125 -0
  539. package/src/db/index.ts +37 -0
  540. package/src/db/libsql.ts +23 -0
  541. package/src/db/postgres.ts +30 -0
  542. package/src/db/sqlite.ts +27 -0
  543. package/src/emdash-runtime.ts +2096 -0
  544. package/src/fields/boolean.ts +34 -0
  545. package/src/fields/datetime.ts +44 -0
  546. package/src/fields/file.ts +41 -0
  547. package/src/fields/image.ts +34 -0
  548. package/src/fields/index.ts +42 -0
  549. package/src/fields/integer.ts +50 -0
  550. package/src/fields/json.ts +37 -0
  551. package/src/fields/multiselect.ts +48 -0
  552. package/src/fields/number.ts +52 -0
  553. package/src/fields/portable-text.ts +33 -0
  554. package/src/fields/reference.ts +29 -0
  555. package/src/fields/richtext.ts +31 -0
  556. package/src/fields/select.ts +46 -0
  557. package/src/fields/slug.ts +38 -0
  558. package/src/fields/text.ts +55 -0
  559. package/src/fields/textarea.ts +52 -0
  560. package/src/fields/types.ts +64 -0
  561. package/src/i18n/config.ts +68 -0
  562. package/src/import/index.ts +90 -0
  563. package/src/import/menus.ts +436 -0
  564. package/src/import/registry.ts +111 -0
  565. package/src/import/sections.ts +103 -0
  566. package/src/import/settings.ts +281 -0
  567. package/src/import/sources/wordpress-plugin.ts +641 -0
  568. package/src/import/sources/wordpress-rest.ts +191 -0
  569. package/src/import/sources/wxr.ts +330 -0
  570. package/src/import/ssrf.ts +260 -0
  571. package/src/import/types.ts +418 -0
  572. package/src/import/utils.ts +412 -0
  573. package/src/index.ts +481 -0
  574. package/src/loader.ts +770 -0
  575. package/src/mcp/server.ts +1463 -0
  576. package/src/media/index.ts +32 -0
  577. package/src/media/local-runtime.ts +213 -0
  578. package/src/media/local.ts +46 -0
  579. package/src/media/normalize.ts +190 -0
  580. package/src/media/placeholder.ts +150 -0
  581. package/src/media/provider-loader.ts +78 -0
  582. package/src/media/types.ts +279 -0
  583. package/src/menus/index.ts +324 -0
  584. package/src/menus/types.ts +112 -0
  585. package/src/page/context.ts +93 -0
  586. package/src/page/fragments.ts +89 -0
  587. package/src/page/index.ts +58 -0
  588. package/src/page/jsonld.ts +94 -0
  589. package/src/page/metadata.ts +185 -0
  590. package/src/page/seo-contributions.ts +136 -0
  591. package/src/plugin-utils.ts +80 -0
  592. package/src/plugins/adapt-sandbox-entry.ts +207 -0
  593. package/src/plugins/context.ts +833 -0
  594. package/src/plugins/cron.ts +361 -0
  595. package/src/plugins/define-plugin.ts +259 -0
  596. package/src/plugins/email-console.ts +73 -0
  597. package/src/plugins/email.ts +209 -0
  598. package/src/plugins/hooks.ts +1273 -0
  599. package/src/plugins/index.ts +193 -0
  600. package/src/plugins/manager.ts +595 -0
  601. package/src/plugins/manifest-schema.ts +230 -0
  602. package/src/plugins/marketplace.ts +460 -0
  603. package/src/plugins/request-meta.ts +139 -0
  604. package/src/plugins/routes.ts +302 -0
  605. package/src/plugins/sandbox/index.ts +18 -0
  606. package/src/plugins/sandbox/noop.ts +76 -0
  607. package/src/plugins/sandbox/types.ts +173 -0
  608. package/src/plugins/scheduler/node.ts +122 -0
  609. package/src/plugins/scheduler/piggyback.ts +71 -0
  610. package/src/plugins/scheduler/types.ts +27 -0
  611. package/src/plugins/state.ts +208 -0
  612. package/src/plugins/storage-indexes.ts +326 -0
  613. package/src/plugins/storage-query.ts +240 -0
  614. package/src/plugins/types.ts +1284 -0
  615. package/src/preview/helpers.ts +27 -0
  616. package/src/preview/index.ts +40 -0
  617. package/src/preview/tokens.ts +279 -0
  618. package/src/preview/urls.ts +118 -0
  619. package/src/query.ts +674 -0
  620. package/src/redirects/patterns.ts +224 -0
  621. package/src/request-context.ts +67 -0
  622. package/src/runtime.ts +21 -0
  623. package/src/schema/index.ts +29 -0
  624. package/src/schema/query.ts +44 -0
  625. package/src/schema/registry.ts +965 -0
  626. package/src/schema/types.ts +276 -0
  627. package/src/schema/zod-generator.ts +413 -0
  628. package/src/search/fts-manager.ts +452 -0
  629. package/src/search/index.ts +26 -0
  630. package/src/search/query.ts +396 -0
  631. package/src/search/text-extraction.ts +162 -0
  632. package/src/search/types.ts +114 -0
  633. package/src/sections/index.ts +226 -0
  634. package/src/sections/types.ts +86 -0
  635. package/src/seed/apply.ts +1141 -0
  636. package/src/seed/default.ts +86 -0
  637. package/src/seed/index.ts +28 -0
  638. package/src/seed/load.ts +35 -0
  639. package/src/seed/types.ts +341 -0
  640. package/src/seed/validate.ts +642 -0
  641. package/src/seo/index.ts +179 -0
  642. package/src/settings/index.ts +203 -0
  643. package/src/settings/types.ts +58 -0
  644. package/src/storage/index.ts +28 -0
  645. package/src/storage/local.ts +249 -0
  646. package/src/storage/s3.ts +263 -0
  647. package/src/storage/types.ts +204 -0
  648. package/src/taxonomies/index.ts +309 -0
  649. package/src/taxonomies/types.ts +61 -0
  650. package/src/ui.ts +75 -0
  651. package/src/utils/base64.ts +73 -0
  652. package/src/utils/hash.ts +36 -0
  653. package/src/utils/sanitize.ts +20 -0
  654. package/src/utils/slugify.ts +29 -0
  655. package/src/utils/url.ts +48 -0
  656. package/src/virtual-modules.d.ts +111 -0
  657. package/src/visual-editing/editable.ts +108 -0
  658. package/src/visual-editing/toolbar.ts +1229 -0
  659. package/src/widgets/components.ts +105 -0
  660. package/src/widgets/index.ts +131 -0
  661. package/src/widgets/types.ts +81 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Search suggestions endpoint - Autocomplete
3
+ *
4
+ * GET /_emdash/api/search/suggest?q=hel&limit=5
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ import { requirePerm } from "#api/authorize.js";
10
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
11
+ import { isParseError, parseQuery } from "#api/parse.js";
12
+ import { searchSuggestQuery } from "#api/schemas.js";
13
+ import { getSuggestions } from "#search/index.js";
14
+
15
+ export const prerender = false;
16
+
17
+ /**
18
+ * Get search suggestions for autocomplete
19
+ *
20
+ * Query parameters:
21
+ * - q: Partial search query (required)
22
+ * - collections: Comma-separated list of collection slugs (optional)
23
+ * - limit: Maximum suggestions (optional, defaults to 5)
24
+ */
25
+ export const GET: APIRoute = async ({ url, locals }) => {
26
+ const { emdash, user } = locals;
27
+
28
+ const denied = requirePerm(user, "search:read");
29
+ if (denied) return denied;
30
+
31
+ if (!emdash?.db) {
32
+ return apiError("NOT_CONFIGURED", "EmDash not configured", 500);
33
+ }
34
+
35
+ const query = parseQuery(url, searchSuggestQuery);
36
+ if (isParseError(query)) return query;
37
+
38
+ const collections = query.collections
39
+ ? query.collections.split(",").map((c: string) => c.trim())
40
+ : undefined;
41
+
42
+ try {
43
+ const suggestions = await getSuggestions(emdash.db, query.q, {
44
+ collections,
45
+ locale: query.locale,
46
+ limit: query.limit,
47
+ });
48
+
49
+ return apiSuccess({ items: suggestions });
50
+ } catch (error) {
51
+ return handleError(error, "Failed to get suggestions", "SUGGESTION_ERROR");
52
+ }
53
+ };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Section by slug endpoints
3
+ *
4
+ * GET /_emdash/api/sections/:slug - Get section
5
+ * PUT /_emdash/api/sections/:slug - Update section
6
+ * DELETE /_emdash/api/sections/:slug - Delete section
7
+ */
8
+
9
+ import type { APIRoute } from "astro";
10
+
11
+ import { requirePerm } from "#api/authorize.js";
12
+ import { apiError, handleError, unwrapResult } from "#api/error.js";
13
+ import {
14
+ handleSectionDelete,
15
+ handleSectionGet,
16
+ handleSectionUpdate,
17
+ } from "#api/handlers/sections.js";
18
+ import { isParseError, parseBody } from "#api/parse.js";
19
+ import { updateSectionBody } from "#api/schemas.js";
20
+
21
+ export const prerender = false;
22
+
23
+ export const GET: APIRoute = async ({ params, locals }) => {
24
+ const { emdash, user } = locals;
25
+ const db = emdash.db;
26
+ const { slug } = params;
27
+
28
+ const denied = requirePerm(user, "sections:read");
29
+ if (denied) return denied;
30
+
31
+ if (!slug) {
32
+ return apiError("VALIDATION_ERROR", "slug is required", 400);
33
+ }
34
+
35
+ try {
36
+ const result = await handleSectionGet(db, slug);
37
+ return unwrapResult(result);
38
+ } catch (error) {
39
+ return handleError(error, "Failed to fetch section", "SECTION_GET_ERROR");
40
+ }
41
+ };
42
+
43
+ export const PUT: APIRoute = async ({ params, request, locals }) => {
44
+ const { emdash, user } = locals;
45
+ const db = emdash.db;
46
+ const { slug } = params;
47
+
48
+ const denied = requirePerm(user, "sections:manage");
49
+ if (denied) return denied;
50
+
51
+ if (!slug) {
52
+ return apiError("VALIDATION_ERROR", "slug is required", 400);
53
+ }
54
+
55
+ try {
56
+ const body = await parseBody(request, updateSectionBody);
57
+ if (isParseError(body)) return body;
58
+
59
+ const result = await handleSectionUpdate(db, slug, body);
60
+ return unwrapResult(result);
61
+ } catch (error) {
62
+ return handleError(error, "Failed to update section", "SECTION_UPDATE_ERROR");
63
+ }
64
+ };
65
+
66
+ export const DELETE: APIRoute = async ({ params, locals }) => {
67
+ const { emdash, user } = locals;
68
+ const db = emdash.db;
69
+ const { slug } = params;
70
+
71
+ const denied = requirePerm(user, "sections:manage");
72
+ if (denied) return denied;
73
+
74
+ if (!slug) {
75
+ return apiError("VALIDATION_ERROR", "slug is required", 400);
76
+ }
77
+
78
+ try {
79
+ const result = await handleSectionDelete(db, slug);
80
+ return unwrapResult(result);
81
+ } catch (error) {
82
+ return handleError(error, "Failed to delete section", "SECTION_DELETE_ERROR");
83
+ }
84
+ };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Sections list and create endpoints
3
+ *
4
+ * GET /_emdash/api/sections - List all sections (with filters)
5
+ * POST /_emdash/api/sections - Create section
6
+ */
7
+
8
+ import type { APIRoute } from "astro";
9
+
10
+ import { requirePerm } from "#api/authorize.js";
11
+ import { handleError, unwrapResult } from "#api/error.js";
12
+ import { handleSectionCreate, handleSectionList } from "#api/handlers/sections.js";
13
+ import { isParseError, parseBody, parseQuery } from "#api/parse.js";
14
+ import { createSectionBody, sectionsListQuery } from "#api/schemas.js";
15
+
16
+ export const prerender = false;
17
+
18
+ export const GET: APIRoute = async ({ url, locals }) => {
19
+ const { emdash, user } = locals;
20
+ const db = emdash.db;
21
+
22
+ const denied = requirePerm(user, "sections:read");
23
+ if (denied) return denied;
24
+
25
+ try {
26
+ const query = parseQuery(url, sectionsListQuery);
27
+ if (isParseError(query)) return query;
28
+
29
+ const result = await handleSectionList(db, query);
30
+ return unwrapResult(result);
31
+ } catch (error) {
32
+ return handleError(error, "Failed to fetch sections", "SECTION_LIST_ERROR");
33
+ }
34
+ };
35
+
36
+ export const POST: APIRoute = async ({ request, locals }) => {
37
+ const { emdash, user } = locals;
38
+ const db = emdash.db;
39
+
40
+ const denied = requirePerm(user, "sections:manage");
41
+ if (denied) return denied;
42
+
43
+ try {
44
+ const body = await parseBody(request, createSectionBody);
45
+ if (isParseError(body)) return body;
46
+
47
+ const result = await handleSectionCreate(db, body);
48
+ return unwrapResult(result, 201);
49
+ } catch (error) {
50
+ return handleError(error, "Failed to create section", "SECTION_CREATE_ERROR");
51
+ }
52
+ };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Email Settings API endpoint
3
+ *
4
+ * GET /_emdash/api/settings/email — current provider, available providers, middleware
5
+ * POST /_emdash/api/settings/email/test — send a test email through the full pipeline
6
+ */
7
+
8
+ import { escapeHtml } from "@emdash-cms/auth";
9
+ import type { APIRoute } from "astro";
10
+ import { z } from "zod";
11
+
12
+ import { requirePerm } from "#api/authorize.js";
13
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
14
+ import { isParseError, parseBody } from "#api/parse.js";
15
+ import { OptionsRepository } from "#db/repositories/options.js";
16
+
17
+ export const prerender = false;
18
+
19
+ const EMAIL_DELIVER_HOOK = "email:deliver";
20
+ const EMAIL_BEFORE_SEND_HOOK = "email:beforeSend";
21
+ const EMAIL_AFTER_SEND_HOOK = "email:afterSend";
22
+
23
+ /**
24
+ * GET /_emdash/api/settings/email
25
+ *
26
+ * Returns the email configuration state:
27
+ * - Current provider selection
28
+ * - Available providers (plugins with email:deliver)
29
+ * - Active middleware (email:beforeSend / email:afterSend plugins)
30
+ * - Whether email is available
31
+ */
32
+ export const GET: APIRoute = async ({ locals }) => {
33
+ const { emdash, user } = locals;
34
+
35
+ if (!emdash?.db) {
36
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
37
+ }
38
+
39
+ const denied = requirePerm(user, "settings:manage");
40
+ if (denied) return denied;
41
+
42
+ try {
43
+ const pipeline = emdash.hooks;
44
+ const optionsRepo = new OptionsRepository(emdash.db);
45
+
46
+ // Get email:deliver providers and current selection
47
+ const providers = pipeline.getExclusiveHookProviders(EMAIL_DELIVER_HOOK);
48
+ const selectedProviderId = await optionsRepo.get<string>(
49
+ `emdash:exclusive_hook:${EMAIL_DELIVER_HOOK}`,
50
+ );
51
+
52
+ // Get middleware hooks (beforeSend / afterSend)
53
+ const beforeSendPlugins = pipeline
54
+ .getExclusiveHookProviders(EMAIL_BEFORE_SEND_HOOK)
55
+ .map((p) => p.pluginId);
56
+ const afterSendPlugins = pipeline
57
+ .getExclusiveHookProviders(EMAIL_AFTER_SEND_HOOK)
58
+ .map((p) => p.pluginId);
59
+
60
+ // Note: beforeSend/afterSend are NOT exclusive hooks, but getExclusiveHookProviders
61
+ // only finds exclusive ones. We need all hooks for those names.
62
+ // For now, report what we can from the exclusive hook system.
63
+ // Middleware is non-exclusive so we'd need a different query.
64
+ // TODO: Add getHookProviders() for non-exclusive hooks to the pipeline.
65
+
66
+ return apiSuccess({
67
+ available: emdash.email?.isAvailable() ?? false,
68
+ providers: providers.map((p) => ({
69
+ pluginId: p.pluginId,
70
+ })),
71
+ selectedProviderId: selectedProviderId ?? null,
72
+ middleware: {
73
+ beforeSend: beforeSendPlugins,
74
+ afterSend: afterSendPlugins,
75
+ },
76
+ });
77
+ } catch (error) {
78
+ return handleError(error, "Failed to get email settings", "EMAIL_SETTINGS_READ_ERROR");
79
+ }
80
+ };
81
+
82
+ /**
83
+ * POST /_emdash/api/settings/email/test
84
+ *
85
+ * Send a test email through the full pipeline.
86
+ * Validates the pipeline is configured and the provider works.
87
+ */
88
+ const testEmailBody = z.object({
89
+ to: z.string().email(),
90
+ });
91
+
92
+ export const POST: APIRoute = async ({ request, locals }) => {
93
+ const { emdash, user } = locals;
94
+
95
+ if (!emdash?.db) {
96
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
97
+ }
98
+
99
+ const denied = requirePerm(user, "settings:manage");
100
+ if (denied) return denied;
101
+
102
+ if (!emdash.email?.isAvailable()) {
103
+ return apiError(
104
+ "EMAIL_NOT_CONFIGURED",
105
+ "No email provider is configured. Install and activate an email provider plugin.",
106
+ 503,
107
+ );
108
+ }
109
+
110
+ try {
111
+ const body = await parseBody(request, testEmailBody);
112
+ if (isParseError(body)) return body;
113
+
114
+ const optionsRepo = new OptionsRepository(emdash.db);
115
+ const siteName = (await optionsRepo.get<string>("emdash:site_title")) ?? "EmDash";
116
+ const safeName = escapeHtml(siteName);
117
+
118
+ await emdash.email.send(
119
+ {
120
+ to: body.to,
121
+ subject: `Test email from ${siteName}`,
122
+ text: `This is a test email from ${siteName}.\n\nIf you received this, your email provider is working correctly.`,
123
+ html: `
124
+ <!DOCTYPE html>
125
+ <html>
126
+ <head>
127
+ <meta charset="utf-8">
128
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
129
+ </head>
130
+ <body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.5; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
131
+ <h1 style="font-size: 24px; margin-bottom: 20px;">Test Email</h1>
132
+ <p>This is a test email from <strong>${safeName}</strong>.</p>
133
+ <p>If you received this, your email provider is working correctly.</p>
134
+ <p style="color: #666; font-size: 14px; margin-top: 30px;">
135
+ Sent via the EmDash email pipeline.
136
+ </p>
137
+ </body>
138
+ </html>`,
139
+ },
140
+ "admin",
141
+ );
142
+
143
+ return apiSuccess({
144
+ success: true,
145
+ message: `Test email sent to ${body.to}`,
146
+ });
147
+ } catch (error) {
148
+ return handleError(error, "Failed to send test email", "EMAIL_TEST_ERROR");
149
+ }
150
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Site Settings API endpoint
3
+ *
4
+ * GET /_emdash/api/settings - Get all site settings
5
+ * POST /_emdash/api/settings - Update site settings
6
+ */
7
+
8
+ import type { APIRoute } from "astro";
9
+
10
+ import { requirePerm } from "#api/authorize.js";
11
+ import { apiError, handleError, unwrapResult } from "#api/error.js";
12
+ import { handleSettingsGet, handleSettingsUpdate } from "#api/handlers/settings.js";
13
+ import { isParseError, parseBody } from "#api/parse.js";
14
+ import { settingsUpdateBody } from "#api/schemas.js";
15
+
16
+ export const prerender = false;
17
+
18
+ /**
19
+ * GET /_emdash/api/settings
20
+ *
21
+ * Returns all site settings as a JSON object.
22
+ * Unset values are undefined. Media references include resolved URLs.
23
+ */
24
+ export const GET: APIRoute = async ({ locals }) => {
25
+ const { emdash, user } = locals;
26
+
27
+ if (!emdash?.db) {
28
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
29
+ }
30
+
31
+ const denied = requirePerm(user, "settings:read");
32
+ if (denied) return denied;
33
+
34
+ try {
35
+ const result = await handleSettingsGet(emdash.db, emdash.storage);
36
+ return unwrapResult(result);
37
+ } catch (error) {
38
+ return handleError(error, "Failed to get settings", "SETTINGS_READ_ERROR");
39
+ }
40
+ };
41
+
42
+ /**
43
+ * POST /_emdash/api/settings
44
+ *
45
+ * Updates site settings. Accepts a partial settings object.
46
+ * Merges with existing settings and returns the updated settings.
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
+ const denied = requirePerm(user, "settings:manage");
56
+ if (denied) return denied;
57
+
58
+ try {
59
+ const body = await parseBody(request, settingsUpdateBody);
60
+ if (isParseError(body)) return body;
61
+
62
+ const result = await handleSettingsUpdate(emdash.db, emdash.storage, body);
63
+ return unwrapResult(result);
64
+ } catch (error) {
65
+ return handleError(error, "Failed to update settings", "SETTINGS_UPDATE_ERROR");
66
+ }
67
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * POST /_emdash/api/setup/admin/verify
3
+ *
4
+ * Complete admin creation by verifying the passkey registration
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ export const prerender = false;
10
+
11
+ import { Role } from "@emdash-cms/auth";
12
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
13
+ import { verifyRegistrationResponse, registerPasskey } from "@emdash-cms/auth/passkey";
14
+
15
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
16
+ import { isParseError, parseBody } from "#api/parse.js";
17
+ import { setupAdminVerifyBody } from "#api/schemas.js";
18
+ import { createChallengeStore } from "#auth/challenge-store.js";
19
+ import { getPasskeyConfig } from "#auth/passkey-config.js";
20
+ import { OptionsRepository } from "#db/repositories/options.js";
21
+
22
+ export const POST: APIRoute = async ({ request, locals }) => {
23
+ const { emdash } = locals;
24
+
25
+ if (!emdash?.db) {
26
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
27
+ }
28
+
29
+ try {
30
+ // Check if setup is already complete
31
+ const options = new OptionsRepository(emdash.db);
32
+ const setupComplete = await options.get("emdash:setup_complete");
33
+
34
+ if (setupComplete === true || setupComplete === "true") {
35
+ return apiError("SETUP_COMPLETE", "Setup already complete", 400);
36
+ }
37
+
38
+ // Check if any users exist
39
+ const adapter = createKyselyAdapter(emdash.db);
40
+ const userCount = await adapter.countUsers();
41
+
42
+ if (userCount > 0) {
43
+ return apiError("ADMIN_EXISTS", "Admin user already exists", 400);
44
+ }
45
+
46
+ // Get setup state
47
+ const setupState = await options.get("emdash:setup_state");
48
+
49
+ if (!setupState || setupState.step !== "admin") {
50
+ return apiError("INVALID_STATE", "Invalid setup state. Please restart setup.", 400);
51
+ }
52
+
53
+ // Parse request body
54
+ const body = await parseBody(request, setupAdminVerifyBody);
55
+ if (isParseError(body)) return body;
56
+
57
+ // Get passkey config
58
+ const url = new URL(request.url);
59
+ const siteName = (await options.get<string>("emdash:site_title")) ?? undefined;
60
+ const passkeyConfig = getPasskeyConfig(url, siteName);
61
+
62
+ // Verify the registration response
63
+ const challengeStore = createChallengeStore(emdash.db);
64
+
65
+ const verified = await verifyRegistrationResponse(
66
+ passkeyConfig,
67
+ body.credential,
68
+ challengeStore,
69
+ );
70
+
71
+ // Create the admin user
72
+ const user = await adapter.createUser({
73
+ email: setupState.email,
74
+ name: setupState.name,
75
+ role: Role.ADMIN,
76
+ emailVerified: false, // No email verification for first user
77
+ });
78
+
79
+ // Register the passkey
80
+ await registerPasskey(adapter, user.id, verified, "Setup passkey");
81
+
82
+ // Mark setup as complete
83
+ await options.set("emdash:setup_complete", true);
84
+
85
+ // Clean up setup state
86
+ await options.delete("emdash:setup_state");
87
+
88
+ return apiSuccess({
89
+ success: true,
90
+ user: {
91
+ id: user.id,
92
+ email: user.email,
93
+ name: user.name,
94
+ role: user.role,
95
+ },
96
+ });
97
+ } catch (error) {
98
+ return handleError(error, "Failed to verify admin setup", "SETUP_VERIFY_ERROR");
99
+ }
100
+ };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * POST /_emdash/api/setup/admin
3
+ *
4
+ * Step 3 of setup: Start admin creation by returning passkey registration options
5
+ */
6
+
7
+ import type { APIRoute } from "astro";
8
+
9
+ export const prerender = false;
10
+
11
+ import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
12
+ import { generateRegistrationOptions } from "@emdash-cms/auth/passkey";
13
+
14
+ import { apiError, apiSuccess, handleError } from "#api/error.js";
15
+ import { isParseError, parseBody } from "#api/parse.js";
16
+ import { setupAdminBody } from "#api/schemas.js";
17
+ import { createChallengeStore } from "#auth/challenge-store.js";
18
+ import { getPasskeyConfig } from "#auth/passkey-config.js";
19
+ import { OptionsRepository } from "#db/repositories/options.js";
20
+
21
+ export const POST: APIRoute = async ({ request, locals }) => {
22
+ const { emdash } = locals;
23
+
24
+ if (!emdash?.db) {
25
+ return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
26
+ }
27
+
28
+ try {
29
+ // Check if setup is already complete
30
+ const options = new OptionsRepository(emdash.db);
31
+ const setupComplete = await options.get("emdash:setup_complete");
32
+
33
+ if (setupComplete === true || setupComplete === "true") {
34
+ return apiError("SETUP_COMPLETE", "Setup already complete", 400);
35
+ }
36
+
37
+ // Check if any users exist
38
+ const adapter = createKyselyAdapter(emdash.db);
39
+ const userCount = await adapter.countUsers();
40
+
41
+ if (userCount > 0) {
42
+ return apiError("ADMIN_EXISTS", "Admin user already exists", 400);
43
+ }
44
+
45
+ // Parse request body
46
+ const body = await parseBody(request, setupAdminBody);
47
+ if (isParseError(body)) return body;
48
+
49
+ // Store admin info in setup state for later
50
+ await options.set("emdash:setup_state", {
51
+ step: "admin",
52
+ email: body.email.toLowerCase(),
53
+ name: body.name || null,
54
+ });
55
+
56
+ // Get passkey config
57
+ const url = new URL(request.url);
58
+ const siteName = (await options.get<string>("emdash:site_title")) ?? undefined;
59
+ const passkeyConfig = getPasskeyConfig(url, siteName);
60
+
61
+ // Generate registration options
62
+ const challengeStore = createChallengeStore(emdash.db);
63
+
64
+ // Create a temporary user object for registration options
65
+ // (not persisted until passkey is verified)
66
+ const tempUser = {
67
+ id: `setup-${Date.now()}`, // Temporary ID
68
+ email: body.email.toLowerCase(),
69
+ name: body.name || null,
70
+ };
71
+
72
+ const registrationOptions = await generateRegistrationOptions(
73
+ passkeyConfig,
74
+ tempUser,
75
+ [], // No existing credentials
76
+ challengeStore,
77
+ );
78
+
79
+ // Store the temp user ID with the setup state
80
+ await options.set("emdash:setup_state", {
81
+ step: "admin",
82
+ email: body.email.toLowerCase(),
83
+ name: body.name || null,
84
+ tempUserId: tempUser.id,
85
+ });
86
+
87
+ return apiSuccess({
88
+ success: true,
89
+ options: registrationOptions,
90
+ });
91
+ } catch (error) {
92
+ return handleError(error, "Failed to create admin", "SETUP_ADMIN_ERROR");
93
+ }
94
+ };