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,547 @@
1
+ /**
2
+ * Login/logout/whoami CLI commands
3
+ *
4
+ * Login uses the OAuth Device Flow (RFC 8628):
5
+ * 1. POST /oauth/device/code → get device_code + user_code
6
+ * 2. Display URL + code to user
7
+ * 3. Poll POST /oauth/device/token until authorized
8
+ * 4. Save tokens to ~/.config/emdash/auth.json
9
+ *
10
+ * Custom headers (--header / EMDASH_HEADERS) are sent with every request
11
+ * and persisted to credentials so subsequent commands inherit them.
12
+ * This supports sites behind reverse proxies like Cloudflare Access.
13
+ */
14
+
15
+ import { defineCommand } from "citty";
16
+ import { consola } from "consola";
17
+ import pc from "picocolors";
18
+
19
+ import {
20
+ createHeaderAwareFetch,
21
+ getCachedAccessToken,
22
+ isAccessRedirect,
23
+ resolveCustomHeaders,
24
+ runCloudflaredLogin,
25
+ } from "../../client/cf-access.js";
26
+ import {
27
+ getCredentials,
28
+ removeCredentials,
29
+ resolveCredentialKey,
30
+ saveCredentials,
31
+ } from "../credentials.js";
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Types for discovery + device flow responses
35
+ // ---------------------------------------------------------------------------
36
+
37
+ interface DiscoveryResponse {
38
+ instance?: { name?: string };
39
+ auth?: {
40
+ mode?: string;
41
+ methods?: {
42
+ device_flow?: {
43
+ device_authorization_endpoint: string;
44
+ token_endpoint: string;
45
+ };
46
+ api_tokens?: boolean;
47
+ };
48
+ };
49
+ }
50
+
51
+ interface DeviceCodeResponse {
52
+ device_code: string;
53
+ user_code: string;
54
+ verification_uri: string;
55
+ expires_in: number;
56
+ interval: number;
57
+ }
58
+
59
+ interface TokenResponse {
60
+ access_token: string;
61
+ refresh_token: string;
62
+ token_type: string;
63
+ expires_in: number;
64
+ scope: string;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Device Flow polling
69
+ // ---------------------------------------------------------------------------
70
+
71
+ async function pollForToken(
72
+ tokenEndpoint: string,
73
+ deviceCode: string,
74
+ interval: number,
75
+ expiresIn: number,
76
+ fetchFn: typeof fetch,
77
+ ): Promise<TokenResponse> {
78
+ const deadline = Date.now() + expiresIn * 1000;
79
+ let currentInterval = interval;
80
+
81
+ while (Date.now() < deadline) {
82
+ await new Promise((resolve) => setTimeout(resolve, currentInterval * 1000));
83
+
84
+ const res = await fetchFn(tokenEndpoint, {
85
+ method: "POST",
86
+ headers: { "Content-Type": "application/json" },
87
+ body: JSON.stringify({
88
+ device_code: deviceCode,
89
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
90
+ }),
91
+ });
92
+
93
+ if (res.ok) {
94
+ return (await res.json()) as TokenResponse;
95
+ }
96
+
97
+ const body = (await res.json()) as { error?: string; interval?: number };
98
+
99
+ if (body.error === "authorization_pending") {
100
+ // Keep polling
101
+ continue;
102
+ }
103
+
104
+ if (body.error === "slow_down") {
105
+ // Use server-provided interval, or fall back to incrementing by 5s
106
+ currentInterval = body.interval ?? currentInterval + 5;
107
+ continue;
108
+ }
109
+
110
+ if (body.error === "expired_token") {
111
+ throw new Error("Device code expired. Please try again.");
112
+ }
113
+
114
+ if (body.error === "access_denied") {
115
+ throw new Error("Authorization was denied.");
116
+ }
117
+
118
+ // Unknown error
119
+ throw new Error(`Token exchange failed: ${body.error || res.statusText}`);
120
+ }
121
+
122
+ throw new Error("Device code expired (timeout). Please try again.");
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Cloudflare Access handling
127
+ // ---------------------------------------------------------------------------
128
+
129
+ /**
130
+ * Handle a Cloudflare Access redirect during login.
131
+ *
132
+ * 1. Try `cloudflared access token` for a cached JWT
133
+ * 2. Try `cloudflared access login` to do the browser flow
134
+ * 3. If cloudflared isn't available, print instructions for service tokens
135
+ *
136
+ * Returns the Access JWT, or null if auth couldn't be resolved.
137
+ */
138
+ async function handleAccessRedirect(baseUrl: string): Promise<string | null> {
139
+ consola.info("This site is behind Cloudflare Access.");
140
+
141
+ // Try cached token first
142
+ const cached = await getCachedAccessToken(baseUrl);
143
+ if (cached) {
144
+ consola.success("Using cached Cloudflare Access token from cloudflared.");
145
+ return cached;
146
+ }
147
+
148
+ // Try interactive login via cloudflared
149
+ consola.info("Launching browser for Cloudflare Access login...");
150
+ const loginOk = await runCloudflaredLogin(baseUrl);
151
+
152
+ if (loginOk) {
153
+ const token = await getCachedAccessToken(baseUrl);
154
+ if (token) {
155
+ consola.success("Cloudflare Access authentication successful.");
156
+ return token;
157
+ }
158
+ }
159
+
160
+ // cloudflared not available or login failed — guide the user
161
+ console.log();
162
+ consola.info("Could not authenticate with Cloudflare Access automatically.");
163
+ consola.info("You have two options:");
164
+ console.log();
165
+ consola.info(` ${pc.bold("Option 1:")} Install cloudflared and run:`);
166
+ console.log(` ${pc.cyan(`cloudflared access login ${baseUrl}`)}`);
167
+ console.log(` ${pc.cyan(`emdash login --url ${baseUrl}`)}`);
168
+ console.log();
169
+ consola.info(` ${pc.bold("Option 2:")} Use a service token:`);
170
+ console.log(
171
+ ` ${pc.cyan(`emdash login --url ${baseUrl} -H "CF-Access-Client-Id: <id>" -H "CF-Access-Client-Secret: <secret>"`)}`,
172
+ );
173
+ console.log();
174
+
175
+ return null;
176
+ }
177
+
178
+ // ---------------------------------------------------------------------------
179
+ // Commands
180
+ // ---------------------------------------------------------------------------
181
+
182
+ export const loginCommand = defineCommand({
183
+ meta: { name: "login", description: "Log in to an EmDash instance" },
184
+ args: {
185
+ url: {
186
+ type: "string",
187
+ alias: "u",
188
+ description: "EmDash instance URL",
189
+ default: "http://localhost:4321",
190
+ },
191
+ header: {
192
+ type: "string",
193
+ alias: "H",
194
+ description: 'Custom header "Name: Value" (repeatable, or use EMDASH_HEADERS env)',
195
+ },
196
+ },
197
+ async run({ args }) {
198
+ const baseUrl = args.url || "http://localhost:4321";
199
+ consola.start(`Connecting to ${baseUrl}...`);
200
+
201
+ // Resolve custom headers from --header flags and EMDASH_HEADERS env
202
+ const customHeaders = resolveCustomHeaders();
203
+ let headerFetch = createHeaderAwareFetch(customHeaders);
204
+
205
+ try {
206
+ // Step 1: Fetch auth discovery.
207
+ // Use redirect: "manual" to detect Cloudflare Access.
208
+ const discoveryUrl = new URL("/_emdash/.well-known/auth", baseUrl);
209
+ let res = await headerFetch(discoveryUrl, { redirect: "manual" });
210
+
211
+ // Handle Cloudflare Access
212
+ if (isAccessRedirect(res)) {
213
+ const accessToken = await handleAccessRedirect(baseUrl);
214
+ if (!accessToken) {
215
+ return; // handleAccessRedirect printed instructions
216
+ }
217
+ // Add the Access token to our custom headers and rebuild the fetch wrapper
218
+ customHeaders["cf-access-token"] = accessToken;
219
+ headerFetch = createHeaderAwareFetch(customHeaders);
220
+ res = await headerFetch(discoveryUrl);
221
+ } else if (res.status === 301 || res.status === 302) {
222
+ // Non-Access redirect — follow it normally
223
+ res = await headerFetch(discoveryUrl);
224
+ }
225
+
226
+ if (!res.ok) {
227
+ if (res.status === 404) {
228
+ const isLocal = baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1");
229
+ if (isLocal) {
230
+ consola.info("Auth discovery not available. Trying dev bypass...");
231
+ const bypassRes = await fetch(new URL("/_emdash/api/auth/dev-bypass", baseUrl), {
232
+ redirect: "manual",
233
+ });
234
+ if (bypassRes.status === 302 || bypassRes.ok) {
235
+ consola.success("Dev bypass available. Client will authenticate automatically.");
236
+ } else {
237
+ consola.error("Could not authenticate. Is the dev server running?");
238
+ }
239
+ } else {
240
+ consola.error("Auth discovery endpoint not found. Is this an EmDash instance?");
241
+ }
242
+ return;
243
+ }
244
+ consola.error(`Discovery failed: ${res.status} ${res.statusText}`);
245
+ process.exit(2);
246
+ }
247
+
248
+ const discovery = (await res.json()) as DiscoveryResponse;
249
+ consola.success(`Connected to ${discovery.instance?.name || "EmDash"}`);
250
+
251
+ const deviceFlow = discovery.auth?.methods?.device_flow;
252
+
253
+ if (!deviceFlow) {
254
+ // No device flow available (external auth mode)
255
+ consola.info("Device Flow is not available for this instance.");
256
+ consola.info("Generate an API token in Settings > API Tokens");
257
+ consola.info(`Then run: ${pc.cyan(`emdash --token <token> --url ${baseUrl}`)}`);
258
+ return;
259
+ }
260
+
261
+ // Step 2: Request device code
262
+ const codeUrl = new URL(deviceFlow.device_authorization_endpoint, baseUrl);
263
+ const codeRes = await headerFetch(codeUrl, {
264
+ method: "POST",
265
+ headers: {
266
+ "Content-Type": "application/json",
267
+ "X-EmDash-Request": "1",
268
+ },
269
+ body: JSON.stringify({
270
+ client_id: "emdash-cli",
271
+ }),
272
+ });
273
+
274
+ if (!codeRes.ok) {
275
+ consola.error(`Failed to request device code: ${codeRes.status}`);
276
+ process.exit(2);
277
+ }
278
+
279
+ const deviceCode = (await codeRes.json()) as DeviceCodeResponse;
280
+
281
+ // Step 3: Display instructions
282
+ console.log();
283
+ consola.info(`Open your browser to:`);
284
+ console.log(` ${pc.cyan(pc.bold(deviceCode.verification_uri))}`);
285
+ console.log();
286
+ consola.info(`Enter code: ${pc.yellow(pc.bold(deviceCode.user_code))}`);
287
+ console.log();
288
+
289
+ // Try to open browser (best-effort)
290
+ try {
291
+ const { execFile } = await import("node:child_process");
292
+ if (process.platform === "darwin") {
293
+ execFile("open", [deviceCode.verification_uri]);
294
+ } else if (process.platform === "win32") {
295
+ execFile("cmd", ["/c", "start", "", deviceCode.verification_uri]);
296
+ } else {
297
+ execFile("xdg-open", [deviceCode.verification_uri]);
298
+ }
299
+ } catch {
300
+ // Ignore — user can open manually
301
+ }
302
+
303
+ // Step 4: Poll for token
304
+ consola.start("Waiting for authorization...");
305
+
306
+ const tokenUrl = new URL(deviceFlow.token_endpoint, baseUrl);
307
+ const tokenResult = await pollForToken(
308
+ tokenUrl.toString(),
309
+ deviceCode.device_code,
310
+ deviceCode.interval,
311
+ deviceCode.expires_in,
312
+ headerFetch,
313
+ );
314
+
315
+ // Step 5: Fetch user info
316
+ let userEmail = "unknown";
317
+ let userRole = "unknown";
318
+ try {
319
+ const meRes = await headerFetch(new URL("/_emdash/api/auth/me", baseUrl), {
320
+ headers: { Authorization: `Bearer ${tokenResult.access_token}` },
321
+ });
322
+ if (meRes.ok) {
323
+ const meJson = (await meRes.json()) as {
324
+ data: { email?: string; role?: number };
325
+ };
326
+ const me = meJson.data;
327
+ userEmail = me.email || "unknown";
328
+ // Map role number to name
329
+ const roleNames: Record<number, string> = {
330
+ 10: "subscriber",
331
+ 20: "contributor",
332
+ 30: "author",
333
+ 40: "editor",
334
+ 50: "admin",
335
+ };
336
+ userRole = (me.role ? roleNames[me.role] : undefined) || "unknown";
337
+ }
338
+ } catch {
339
+ // Non-critical
340
+ }
341
+
342
+ // Step 6: Save credentials (persist custom headers so subsequent commands inherit them)
343
+ const expiresAt = new Date(Date.now() + tokenResult.expires_in * 1000).toISOString();
344
+ const hasCustomHeaders = Object.keys(customHeaders).length > 0;
345
+ saveCredentials(baseUrl, {
346
+ accessToken: tokenResult.access_token,
347
+ refreshToken: tokenResult.refresh_token,
348
+ expiresAt,
349
+ ...(hasCustomHeaders ? { customHeaders } : {}),
350
+ user: { email: userEmail, role: userRole },
351
+ });
352
+
353
+ consola.success(`Logged in as ${pc.bold(userEmail)} (${userRole})`);
354
+ consola.info(`Token saved to ${pc.dim(resolveCredentialKey(baseUrl))}`);
355
+ } catch (error) {
356
+ consola.error(error instanceof Error ? error.message : "Login failed");
357
+ process.exit(2);
358
+ }
359
+ },
360
+ });
361
+
362
+ export const logoutCommand = defineCommand({
363
+ meta: { name: "logout", description: "Log out of an EmDash instance" },
364
+ args: {
365
+ url: {
366
+ type: "string",
367
+ alias: "u",
368
+ description: "EmDash instance URL",
369
+ default: "http://localhost:4321",
370
+ },
371
+ },
372
+ async run({ args }) {
373
+ const baseUrl = args.url || "http://localhost:4321";
374
+
375
+ // Get stored credentials
376
+ const cred = getCredentials(baseUrl);
377
+
378
+ if (!cred) {
379
+ consola.info("No stored credentials found for this instance.");
380
+ return;
381
+ }
382
+
383
+ const headerFetch = createHeaderAwareFetch(cred.customHeaders ?? {});
384
+
385
+ // Revoke tokens server-side (best-effort)
386
+ try {
387
+ // Revoke the refresh token (which also revokes associated access tokens)
388
+ await headerFetch(new URL("/_emdash/api/oauth/token/revoke", baseUrl), {
389
+ method: "POST",
390
+ headers: { "Content-Type": "application/json" },
391
+ body: JSON.stringify({ token: cred.refreshToken }),
392
+ });
393
+ } catch {
394
+ // Non-critical — the local removal still works
395
+ }
396
+
397
+ // Remove local credentials
398
+ removeCredentials(baseUrl);
399
+ consola.success("Logged out successfully.");
400
+ },
401
+ });
402
+
403
+ export const whoamiCommand = defineCommand({
404
+ meta: {
405
+ name: "whoami",
406
+ description: "Show current user and auth method",
407
+ },
408
+ args: {
409
+ url: {
410
+ type: "string",
411
+ alias: "u",
412
+ description: "EmDash instance URL",
413
+ default: "http://localhost:4321",
414
+ },
415
+ token: {
416
+ type: "string",
417
+ alias: "t",
418
+ description: "Auth token",
419
+ },
420
+ json: {
421
+ type: "boolean",
422
+ description: "Output as JSON",
423
+ },
424
+ },
425
+ async run({ args }) {
426
+ const baseUrl = args.url || "http://localhost:4321";
427
+
428
+ // Resolve token: --token flag > EMDASH_TOKEN env > stored credentials
429
+ let token = args.token || process.env["EMDASH_TOKEN"];
430
+ let authMethod = token ? "token" : "none";
431
+ let storedHeaders: Record<string, string> = {};
432
+
433
+ if (!token) {
434
+ const cred = getCredentials(baseUrl);
435
+ if (cred) {
436
+ token = cred.accessToken;
437
+ authMethod = "stored";
438
+ storedHeaders = cred.customHeaders ?? {};
439
+
440
+ // Check if expired
441
+ if (new Date(cred.expiresAt) < new Date()) {
442
+ const headerFetch = createHeaderAwareFetch(storedHeaders);
443
+ // Try to refresh
444
+ try {
445
+ const refreshRes = await headerFetch(
446
+ new URL("/_emdash/api/oauth/token/refresh", baseUrl),
447
+ {
448
+ method: "POST",
449
+ headers: { "Content-Type": "application/json" },
450
+ body: JSON.stringify({
451
+ refresh_token: cred.refreshToken,
452
+ grant_type: "refresh_token",
453
+ }),
454
+ },
455
+ );
456
+ if (refreshRes.ok) {
457
+ const refreshed = (await refreshRes.json()) as TokenResponse;
458
+ token = refreshed.access_token;
459
+ saveCredentials(baseUrl, {
460
+ ...cred,
461
+ accessToken: refreshed.access_token,
462
+ expiresAt: new Date(Date.now() + refreshed.expires_in * 1000).toISOString(),
463
+ });
464
+ } else {
465
+ consola.warn("Stored token expired and refresh failed. Run: emdash login");
466
+ process.exit(2);
467
+ }
468
+ } catch {
469
+ consola.warn("Stored token expired. Run: emdash login");
470
+ process.exit(2);
471
+ }
472
+ }
473
+ }
474
+ }
475
+
476
+ if (!token) {
477
+ // Try dev bypass for local
478
+ const isLocal = baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1");
479
+ if (isLocal) {
480
+ authMethod = "dev-bypass";
481
+ consola.info(`Auth method: ${pc.cyan("dev-bypass")}`);
482
+ consola.info("No stored credentials. Client will use dev bypass for localhost.");
483
+ return;
484
+ }
485
+
486
+ consola.error("Not logged in. Run: emdash login");
487
+ process.exit(2);
488
+ }
489
+
490
+ const headerFetch = createHeaderAwareFetch(storedHeaders);
491
+
492
+ try {
493
+ const meRes = await headerFetch(new URL("/_emdash/api/auth/me", baseUrl), {
494
+ headers: { Authorization: `Bearer ${token}` },
495
+ });
496
+
497
+ if (!meRes.ok) {
498
+ if (meRes.status === 401) {
499
+ consola.error("Token is invalid or expired. Run: emdash login");
500
+ process.exit(1);
501
+ }
502
+ consola.error(`Failed to fetch user info: ${meRes.status}`);
503
+ process.exit(1);
504
+ }
505
+
506
+ const raw = (await meRes.json()) as {
507
+ data: {
508
+ id: string;
509
+ email: string;
510
+ name: string | null;
511
+ role: number;
512
+ };
513
+ };
514
+ const me = raw.data;
515
+
516
+ const roleNames: Record<number, string> = {
517
+ 10: "subscriber",
518
+ 20: "contributor",
519
+ 30: "author",
520
+ 40: "editor",
521
+ 50: "admin",
522
+ };
523
+
524
+ if (args.json) {
525
+ console.log(
526
+ JSON.stringify({
527
+ id: me.id,
528
+ email: me.email,
529
+ name: me.name,
530
+ role: roleNames[me.role] || `unknown (${me.role})`,
531
+ authMethod,
532
+ url: baseUrl,
533
+ }),
534
+ );
535
+ } else {
536
+ consola.info(`Email: ${pc.bold(me.email)}`);
537
+ if (me.name) consola.info(`Name: ${me.name}`);
538
+ consola.info(`Role: ${pc.cyan(roleNames[me.role] || `unknown (${me.role})`)}`);
539
+ consola.info(`Auth: ${pc.dim(authMethod)}`);
540
+ consola.info(`URL: ${pc.dim(baseUrl)}`);
541
+ }
542
+ } catch (error) {
543
+ consola.error(error instanceof Error ? error.message : "Unknown error");
544
+ process.exit(1);
545
+ }
546
+ },
547
+ });
@@ -0,0 +1,165 @@
1
+ /**
2
+ * emdash media
3
+ *
4
+ * Manage media items via the EmDash API
5
+ */
6
+
7
+ import { readFile } from "node:fs/promises";
8
+ import { basename } from "node:path";
9
+
10
+ import { defineCommand } from "citty";
11
+ import { consola } from "consola";
12
+
13
+ import { connectionArgs, createClientFromArgs } from "../client-factory.js";
14
+ import { output } from "../output.js";
15
+
16
+ const listCommand = defineCommand({
17
+ meta: {
18
+ name: "list",
19
+ description: "List media items",
20
+ },
21
+ args: {
22
+ ...connectionArgs,
23
+ mime: {
24
+ type: "string",
25
+ description: "Filter by MIME type (e.g., image/png)",
26
+ },
27
+ limit: {
28
+ type: "string",
29
+ description: "Number of items to return",
30
+ },
31
+ cursor: {
32
+ type: "string",
33
+ description: "Pagination cursor",
34
+ },
35
+ },
36
+ async run({ args }) {
37
+ const client = createClientFromArgs(args);
38
+
39
+ try {
40
+ const result = await client.mediaList({
41
+ mimeType: args.mime,
42
+ limit: args.limit ? Number(args.limit) : undefined,
43
+ cursor: args.cursor,
44
+ });
45
+
46
+ output(result, args);
47
+ } catch (error) {
48
+ consola.error("Failed to list media:", error instanceof Error ? error.message : error);
49
+ process.exit(1);
50
+ }
51
+ },
52
+ });
53
+
54
+ const uploadCommand = defineCommand({
55
+ meta: {
56
+ name: "upload",
57
+ description: "Upload a media file",
58
+ },
59
+ args: {
60
+ file: {
61
+ type: "positional",
62
+ description: "Path to the file to upload",
63
+ required: true,
64
+ },
65
+ ...connectionArgs,
66
+ alt: {
67
+ type: "string",
68
+ description: "Alt text for the media item",
69
+ },
70
+ caption: {
71
+ type: "string",
72
+ description: "Caption for the media item",
73
+ },
74
+ },
75
+ async run({ args }) {
76
+ const client = createClientFromArgs(args);
77
+ const filename = basename(args.file);
78
+
79
+ consola.start(`Uploading ${filename}...`);
80
+
81
+ try {
82
+ const buffer = await readFile(args.file);
83
+ const result = await client.mediaUpload(buffer, filename, {
84
+ alt: args.alt,
85
+ caption: args.caption,
86
+ });
87
+
88
+ consola.success(`Uploaded ${filename}`);
89
+ output(result, args);
90
+ } catch (error) {
91
+ consola.error("Failed to upload:", error instanceof Error ? error.message : error);
92
+ process.exit(1);
93
+ }
94
+ },
95
+ });
96
+
97
+ const getCommand = defineCommand({
98
+ meta: {
99
+ name: "get",
100
+ description: "Get a media item",
101
+ },
102
+ args: {
103
+ id: {
104
+ type: "positional",
105
+ description: "Media item ID",
106
+ required: true,
107
+ },
108
+ ...connectionArgs,
109
+ },
110
+ async run({ args }) {
111
+ const client = createClientFromArgs(args);
112
+
113
+ try {
114
+ const result = await client.mediaGet(args.id);
115
+ output(result, args);
116
+ } catch (error) {
117
+ consola.error("Failed to get media:", error instanceof Error ? error.message : error);
118
+ process.exit(1);
119
+ }
120
+ },
121
+ });
122
+
123
+ const deleteCommand = defineCommand({
124
+ meta: {
125
+ name: "delete",
126
+ description: "Delete a media item",
127
+ },
128
+ args: {
129
+ id: {
130
+ type: "positional",
131
+ description: "Media item ID",
132
+ required: true,
133
+ },
134
+ ...connectionArgs,
135
+ },
136
+ async run({ args }) {
137
+ const client = createClientFromArgs(args);
138
+
139
+ try {
140
+ await client.mediaDelete(args.id);
141
+
142
+ if (args.json) {
143
+ output({ deleted: true }, args);
144
+ } else {
145
+ consola.success(`Deleted media item ${args.id}`);
146
+ }
147
+ } catch (error) {
148
+ consola.error("Failed to delete media:", error instanceof Error ? error.message : error);
149
+ process.exit(1);
150
+ }
151
+ },
152
+ });
153
+
154
+ export const mediaCommand = defineCommand({
155
+ meta: {
156
+ name: "media",
157
+ description: "Manage media items",
158
+ },
159
+ subCommands: {
160
+ list: listCommand,
161
+ upload: uploadCommand,
162
+ get: getCommand,
163
+ delete: deleteCommand,
164
+ },
165
+ });