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,699 @@
1
+ /**
2
+ * emdash plugin publish
3
+ *
4
+ * Publishes a plugin tarball to the EmDash Marketplace.
5
+ *
6
+ * Flow:
7
+ * 1. Resolve tarball (from --tarball path, or build via `emdash plugin bundle`)
8
+ * 2. Read manifest.json from tarball to show summary
9
+ * 3. Authenticate (stored credential or GitHub device flow)
10
+ * 4. Pre-publish validation (check plugin exists, version not published)
11
+ * 5. Upload via multipart POST
12
+ * 6. Display audit results
13
+ */
14
+
15
+ import { readFile, stat } from "node:fs/promises";
16
+ import { resolve, basename } from "node:path";
17
+
18
+ import { defineCommand } from "citty";
19
+ import consola from "consola";
20
+ import { createGzipDecoder, unpackTar } from "modern-tar";
21
+ import pc from "picocolors";
22
+
23
+ import { pluginManifestSchema } from "../../plugins/manifest-schema.js";
24
+ import {
25
+ getMarketplaceCredential,
26
+ saveMarketplaceCredential,
27
+ removeMarketplaceCredential,
28
+ } from "../credentials.js";
29
+
30
+ const DEFAULT_REGISTRY = "https://marketplace.emdashcms.com";
31
+
32
+ // ── GitHub Device Flow ──────────────────────────────────────────
33
+
34
+ interface DeviceCodeResponse {
35
+ device_code: string;
36
+ user_code: string;
37
+ verification_uri: string;
38
+ expires_in: number;
39
+ interval: number;
40
+ }
41
+
42
+ interface GitHubTokenResponse {
43
+ access_token?: string;
44
+ token_type?: string;
45
+ error?: string;
46
+ error_description?: string;
47
+ interval?: number;
48
+ }
49
+
50
+ interface MarketplaceAuthResponse {
51
+ token: string;
52
+ author: {
53
+ id: string;
54
+ name: string;
55
+ avatarUrl: string;
56
+ };
57
+ }
58
+
59
+ interface AuthDiscovery {
60
+ github: {
61
+ clientId: string;
62
+ deviceAuthorizationEndpoint: string;
63
+ tokenEndpoint: string;
64
+ };
65
+ marketplace: {
66
+ deviceTokenEndpoint: string;
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Authenticate with the marketplace via GitHub Device Flow.
72
+ * Returns the marketplace JWT and author info.
73
+ */
74
+ async function authenticateViaDeviceFlow(registryUrl: string): Promise<MarketplaceAuthResponse> {
75
+ // Step 1: Fetch auth discovery to get GitHub client_id
76
+ consola.start("Fetching auth configuration...");
77
+ const discoveryRes = await fetch(new URL("/api/v1/auth/discovery", registryUrl));
78
+ if (!discoveryRes.ok) {
79
+ throw new Error(`Marketplace unreachable: ${discoveryRes.status} ${discoveryRes.statusText}`);
80
+ }
81
+ const discovery = (await discoveryRes.json()) as AuthDiscovery;
82
+
83
+ // Step 2: Request device code from GitHub
84
+ const deviceRes = await fetch(discovery.github.deviceAuthorizationEndpoint, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ Accept: "application/json",
89
+ },
90
+ body: JSON.stringify({
91
+ client_id: discovery.github.clientId,
92
+ scope: "read:user user:email",
93
+ }),
94
+ });
95
+
96
+ if (!deviceRes.ok) {
97
+ throw new Error(`GitHub device flow failed: ${deviceRes.status}`);
98
+ }
99
+
100
+ const deviceCode = (await deviceRes.json()) as DeviceCodeResponse;
101
+
102
+ // Step 3: Display instructions
103
+ console.log();
104
+ consola.info("Open your browser to:");
105
+ console.log(` ${pc.cyan(pc.bold(deviceCode.verification_uri))}`);
106
+ console.log();
107
+ consola.info(`Enter code: ${pc.yellow(pc.bold(deviceCode.user_code))}`);
108
+ console.log();
109
+
110
+ // Try to open browser
111
+ try {
112
+ const { execFile } = await import("node:child_process");
113
+ if (process.platform === "darwin") {
114
+ execFile("open", [deviceCode.verification_uri]);
115
+ } else if (process.platform === "win32") {
116
+ execFile("cmd", ["/c", "start", "", deviceCode.verification_uri]);
117
+ } else {
118
+ execFile("xdg-open", [deviceCode.verification_uri]);
119
+ }
120
+ } catch {
121
+ // User can open manually
122
+ }
123
+
124
+ // Step 4: Poll GitHub for access token
125
+ consola.start("Waiting for authorization...");
126
+ const githubToken = await pollGitHubDeviceFlow(
127
+ discovery.github.tokenEndpoint,
128
+ discovery.github.clientId,
129
+ deviceCode.device_code,
130
+ deviceCode.interval,
131
+ deviceCode.expires_in,
132
+ );
133
+
134
+ // Step 5: Exchange GitHub token for marketplace JWT
135
+ consola.start("Authenticating with marketplace...");
136
+ const deviceTokenUrl = new URL(discovery.marketplace.deviceTokenEndpoint, registryUrl);
137
+ const authRes = await fetch(deviceTokenUrl, {
138
+ method: "POST",
139
+ headers: { "Content-Type": "application/json" },
140
+ body: JSON.stringify({ access_token: githubToken }),
141
+ });
142
+
143
+ if (!authRes.ok) {
144
+ const body = (await authRes.json().catch(() => ({}))) as { error?: string };
145
+ throw new Error(`Marketplace auth failed: ${body.error ?? authRes.statusText}`);
146
+ }
147
+
148
+ return (await authRes.json()) as MarketplaceAuthResponse;
149
+ }
150
+
151
+ async function pollGitHubDeviceFlow(
152
+ tokenEndpoint: string,
153
+ clientId: string,
154
+ deviceCode: string,
155
+ interval: number,
156
+ expiresIn: number,
157
+ ): Promise<string> {
158
+ const deadline = Date.now() + expiresIn * 1000;
159
+ let currentInterval = interval;
160
+
161
+ while (Date.now() < deadline) {
162
+ await new Promise((r) => setTimeout(r, currentInterval * 1000));
163
+
164
+ const res = await fetch(tokenEndpoint, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ Accept: "application/json",
169
+ },
170
+ body: JSON.stringify({
171
+ client_id: clientId,
172
+ device_code: deviceCode,
173
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
174
+ }),
175
+ });
176
+
177
+ const body = (await res.json()) as GitHubTokenResponse;
178
+
179
+ if (body.access_token) {
180
+ return body.access_token;
181
+ }
182
+
183
+ if (body.error === "authorization_pending") continue;
184
+ if (body.error === "slow_down") {
185
+ currentInterval = body.interval ?? currentInterval + 5;
186
+ continue;
187
+ }
188
+ if (body.error === "expired_token") {
189
+ throw new Error("Device code expired. Please try again.");
190
+ }
191
+ if (body.error === "access_denied") {
192
+ throw new Error("Authorization was denied.");
193
+ }
194
+
195
+ throw new Error(`GitHub token exchange failed: ${body.error ?? "unknown error"}`);
196
+ }
197
+
198
+ throw new Error("Device code expired (timeout). Please try again.");
199
+ }
200
+
201
+ // ── Tarball reading ─────────────────────────────────────────────
202
+
203
+ const manifestSummarySchema = pluginManifestSchema.pick({
204
+ id: true,
205
+ version: true,
206
+ capabilities: true,
207
+ allowedHosts: true,
208
+ });
209
+
210
+ type ManifestSummary = typeof manifestSummarySchema._zod.output;
211
+
212
+ /**
213
+ * Read manifest.json from a tarball without fully extracting it.
214
+ */
215
+ async function readManifestFromTarball(tarballPath: string): Promise<ManifestSummary> {
216
+ const data = await readFile(tarballPath);
217
+ const stream = new ReadableStream<Uint8Array>({
218
+ start(controller) {
219
+ controller.enqueue(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
220
+ controller.close();
221
+ },
222
+ });
223
+
224
+ const entries = await unpackTar(stream.pipeThrough(createGzipDecoder()), {
225
+ filter: (header) => header.name === "manifest.json",
226
+ });
227
+
228
+ const manifest = entries.find((e) => e.header.name === "manifest.json");
229
+ if (!manifest?.data) {
230
+ throw new Error("Tarball does not contain manifest.json");
231
+ }
232
+
233
+ const content = new TextDecoder().decode(manifest.data);
234
+ const parsed: unknown = JSON.parse(content);
235
+ const result = manifestSummarySchema.safeParse(parsed);
236
+ if (!result.success) {
237
+ throw new Error(`Invalid manifest.json: ${result.error.message}`);
238
+ }
239
+ return result.data;
240
+ }
241
+
242
+ // ── Audit polling helpers ───────────────────────────────────────
243
+
244
+ const POLL_INTERVAL_MS = 3000;
245
+ const POLL_TIMEOUT_MS = 120_000; // 2 minutes
246
+
247
+ interface VersionStatusResponse {
248
+ version: string;
249
+ status: string;
250
+ audit_verdict?: string | null;
251
+ audit_id?: string | null;
252
+ image_audit_verdict?: string | null;
253
+ }
254
+
255
+ /**
256
+ * Poll the version endpoint until status leaves "pending" or timeout.
257
+ * Returns the final version data, or null on timeout.
258
+ */
259
+ async function pollVersionStatus(
260
+ versionUrl: string,
261
+ token: string,
262
+ ): Promise<VersionStatusResponse | null> {
263
+ const deadline = Date.now() + POLL_TIMEOUT_MS;
264
+
265
+ while (Date.now() < deadline) {
266
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
267
+
268
+ try {
269
+ const res = await fetch(versionUrl, {
270
+ headers: { Authorization: `Bearer ${token}` },
271
+ });
272
+
273
+ if (!res.ok) continue;
274
+
275
+ const data = (await res.json()) as VersionStatusResponse;
276
+ if (data.status !== "pending") {
277
+ return data;
278
+ }
279
+ } catch {
280
+ // Network error — retry
281
+ }
282
+ }
283
+
284
+ return null;
285
+ }
286
+
287
+ function displayAuditResults(version: VersionStatusResponse): void {
288
+ const statusColor =
289
+ version.status === "published" ? pc.green : version.status === "flagged" ? pc.yellow : pc.red;
290
+ consola.info(` Status: ${statusColor(version.status)}`);
291
+
292
+ if (version.audit_verdict) {
293
+ const verdictColor =
294
+ version.audit_verdict === "pass"
295
+ ? pc.green
296
+ : version.audit_verdict === "warn"
297
+ ? pc.yellow
298
+ : pc.red;
299
+ consola.info(` Audit: ${verdictColor(version.audit_verdict)}`);
300
+ }
301
+
302
+ if (version.image_audit_verdict) {
303
+ const verdictColor =
304
+ version.image_audit_verdict === "pass"
305
+ ? pc.green
306
+ : version.image_audit_verdict === "warn"
307
+ ? pc.yellow
308
+ : pc.red;
309
+ consola.info(` Image audit: ${verdictColor(version.image_audit_verdict)}`);
310
+ }
311
+ }
312
+
313
+ function displayInlineAuditResults(
314
+ audit: {
315
+ verdict: string;
316
+ riskScore: number;
317
+ summary: string;
318
+ findings: { category: string; severity: string; description: string }[];
319
+ },
320
+ imageAudit: { verdict: string } | null,
321
+ ): void {
322
+ const verdictColor =
323
+ audit.verdict === "pass" ? pc.green : audit.verdict === "warn" ? pc.yellow : pc.red;
324
+ consola.info(` Audit: ${verdictColor(audit.verdict)} (risk: ${audit.riskScore}/100)`);
325
+ if (audit.findings.length > 0) {
326
+ for (const finding of audit.findings) {
327
+ const icon = finding.severity === "high" ? pc.red("!") : pc.yellow("~");
328
+ consola.info(` ${icon} [${finding.category}] ${finding.description}`);
329
+ }
330
+ }
331
+
332
+ if (imageAudit) {
333
+ const imgColor =
334
+ imageAudit.verdict === "pass" ? pc.green : imageAudit.verdict === "warn" ? pc.yellow : pc.red;
335
+ consola.info(` Image audit: ${imgColor(imageAudit.verdict)}`);
336
+ }
337
+ }
338
+
339
+ // ── Publish command ─────────────────────────────────────────────
340
+
341
+ export const publishCommand = defineCommand({
342
+ meta: {
343
+ name: "publish",
344
+ description: "Publish a plugin to the EmDash Marketplace",
345
+ },
346
+ args: {
347
+ tarball: {
348
+ type: "string",
349
+ description: "Path to plugin tarball (default: build first via `emdash plugin bundle`)",
350
+ },
351
+ dir: {
352
+ type: "string",
353
+ description: "Plugin directory (used with --build, default: current directory)",
354
+ default: process.cwd(),
355
+ },
356
+ build: {
357
+ type: "boolean",
358
+ description: "Build the plugin before publishing",
359
+ default: false,
360
+ },
361
+ registry: {
362
+ type: "string",
363
+ description: "Marketplace registry URL",
364
+ default: DEFAULT_REGISTRY,
365
+ },
366
+ "no-wait": {
367
+ type: "boolean",
368
+ description: "Exit immediately after upload without waiting for audit (useful for CI)",
369
+ default: false,
370
+ },
371
+ },
372
+ async run({ args }) {
373
+ const registryUrl = args.registry;
374
+
375
+ // ── Step 1: Resolve tarball ──
376
+
377
+ let tarballPath: string;
378
+
379
+ if (args.tarball) {
380
+ tarballPath = resolve(args.tarball);
381
+ } else if (args.build) {
382
+ // Build first, then find the output tarball
383
+ consola.start("Building plugin...");
384
+ const pluginDir = resolve(args.dir);
385
+ try {
386
+ const { runCommand } = await import("citty");
387
+ const { bundleCommand } = await import("./bundle.js");
388
+ await runCommand(bundleCommand, {
389
+ rawArgs: ["--dir", pluginDir],
390
+ });
391
+ } catch {
392
+ consola.error("Build failed");
393
+ process.exit(1);
394
+ }
395
+
396
+ // Find the tarball in dist/
397
+ const { readdir } = await import("node:fs/promises");
398
+ const distDir = resolve(pluginDir, "dist");
399
+ const files = await readdir(distDir);
400
+ const tarball = files.find((f) => f.endsWith(".tar.gz"));
401
+ if (!tarball) {
402
+ consola.error("Build succeeded but no .tar.gz found in dist/");
403
+ process.exit(1);
404
+ }
405
+ tarballPath = resolve(distDir, tarball);
406
+ } else {
407
+ // Look for an existing tarball in dist/
408
+ const pluginDir = resolve(args.dir);
409
+ const { readdir } = await import("node:fs/promises");
410
+ try {
411
+ const distDir = resolve(pluginDir, "dist");
412
+ const files = await readdir(distDir);
413
+ const tarball = files.find((f) => f.endsWith(".tar.gz"));
414
+ if (tarball) {
415
+ tarballPath = resolve(distDir, tarball);
416
+ } else {
417
+ consola.error("No tarball found. Run `emdash plugin bundle` first or use --build.");
418
+ process.exit(1);
419
+ }
420
+ } catch {
421
+ consola.error(
422
+ "No dist/ directory found. Run `emdash plugin bundle` first or use --build.",
423
+ );
424
+ process.exit(1);
425
+ }
426
+ }
427
+
428
+ const tarballStat = await stat(tarballPath);
429
+ const sizeKB = (tarballStat.size / 1024).toFixed(1);
430
+ consola.info(`Tarball: ${pc.dim(tarballPath)} (${sizeKB}KB)`);
431
+
432
+ // ── Step 2: Read manifest from tarball ──
433
+
434
+ const manifest = await readManifestFromTarball(tarballPath);
435
+ console.log();
436
+ consola.info(`Plugin: ${pc.bold(`${manifest.id}@${manifest.version}`)}`);
437
+ if (manifest.capabilities.length > 0) {
438
+ consola.info(`Capabilities: ${manifest.capabilities.join(", ")}`);
439
+ }
440
+ if (manifest.allowedHosts?.length) {
441
+ consola.info(`Allowed hosts: ${manifest.allowedHosts.join(", ")}`);
442
+ }
443
+ console.log();
444
+
445
+ // ── Step 3: Authenticate ──
446
+ //
447
+ // Priority: EMDASH_MARKETPLACE_TOKEN env var > stored credential > interactive device flow.
448
+ // The env var enables CI pipelines (including seed token auth) without interactive login.
449
+
450
+ let token: string;
451
+ const envToken = process.env.EMDASH_MARKETPLACE_TOKEN;
452
+ const stored = !envToken ? getMarketplaceCredential(registryUrl) : null;
453
+
454
+ if (envToken) {
455
+ token = envToken;
456
+ consola.info("Using EMDASH_MARKETPLACE_TOKEN for authentication");
457
+ } else if (stored) {
458
+ token = stored.token;
459
+ consola.info(`Authenticated as ${pc.bold(stored.author?.name ?? "unknown")}`);
460
+ } else {
461
+ consola.info("Not logged in to marketplace. Starting GitHub authentication...");
462
+ const result = await authenticateViaDeviceFlow(registryUrl);
463
+ token = result.token;
464
+
465
+ // Save for next time
466
+ saveMarketplaceCredential(registryUrl, {
467
+ token: result.token,
468
+ expiresAt: new Date(Date.now() + 30 * 86400 * 1000).toISOString(), // 30 days
469
+ author: { id: result.author.id, name: result.author.name },
470
+ });
471
+
472
+ consola.success(`Authenticated as ${pc.bold(result.author.name)}`);
473
+ }
474
+
475
+ // ── Step 4: Pre-publish validation ──
476
+
477
+ consola.start("Checking marketplace...");
478
+
479
+ // Check if plugin exists
480
+ const pluginRes = await fetch(new URL(`/api/v1/plugins/${manifest.id}`, registryUrl));
481
+
482
+ if (pluginRes.status === 404 && !envToken) {
483
+ // Plugin doesn't exist — register it first.
484
+ // When using env token (seed), the server auto-registers on publish.
485
+ consola.info(`Plugin ${pc.bold(manifest.id)} not found in marketplace. Registering...`);
486
+
487
+ const createRes = await fetch(new URL("/api/v1/plugins", registryUrl), {
488
+ method: "POST",
489
+ headers: {
490
+ "Content-Type": "application/json",
491
+ Authorization: `Bearer ${token}`,
492
+ },
493
+ body: JSON.stringify({
494
+ id: manifest.id,
495
+ name: manifest.id, // Use ID as name initially
496
+ capabilities: manifest.capabilities,
497
+ }),
498
+ });
499
+
500
+ if (!createRes.ok) {
501
+ const body = (await createRes.json().catch(() => ({}))) as { error?: string };
502
+ if (createRes.status === 401) {
503
+ // Token expired — clear and retry
504
+ removeMarketplaceCredential(registryUrl);
505
+ consola.error(
506
+ "Authentication expired. Please run `emdash plugin publish` again to re-authenticate.",
507
+ );
508
+ process.exit(1);
509
+ }
510
+ consola.error(`Failed to register plugin: ${body.error ?? createRes.statusText}`);
511
+ process.exit(1);
512
+ }
513
+
514
+ consola.success(`Registered ${pc.bold(manifest.id)}`);
515
+ } else if (pluginRes.status === 404 && envToken) {
516
+ // Using env token — server handles auto-registration on publish
517
+ consola.info(`Plugin ${pc.bold(manifest.id)} will be auto-registered on publish`);
518
+ } else if (!pluginRes.ok) {
519
+ consola.error(`Marketplace error: ${pluginRes.status}`);
520
+ process.exit(1);
521
+ }
522
+
523
+ // ── Step 5: Upload ──
524
+
525
+ consola.start(`Publishing ${manifest.id}@${manifest.version}...`);
526
+
527
+ const tarballData = await readFile(tarballPath);
528
+ const formData = new FormData();
529
+ formData.append(
530
+ "bundle",
531
+ new Blob([tarballData], { type: "application/gzip" }),
532
+ basename(tarballPath),
533
+ );
534
+
535
+ const uploadUrl = new URL(`/api/v1/plugins/${manifest.id}/versions`, registryUrl);
536
+ const uploadRes = await fetch(uploadUrl, {
537
+ method: "POST",
538
+ headers: {
539
+ Authorization: `Bearer ${token}`,
540
+ },
541
+ body: formData,
542
+ });
543
+
544
+ if (!uploadRes.ok && uploadRes.status !== 202) {
545
+ const body = (await uploadRes.json().catch(() => ({}))) as {
546
+ error?: string;
547
+ latestVersion?: string;
548
+ audit?: { verdict: string; summary: string; findings: unknown[] };
549
+ };
550
+
551
+ if (uploadRes.status === 401) {
552
+ if (envToken) {
553
+ consola.error("EMDASH_MARKETPLACE_TOKEN was rejected by the marketplace.");
554
+ } else {
555
+ removeMarketplaceCredential(registryUrl);
556
+ consola.error("Authentication expired. Please run `emdash plugin publish` again.");
557
+ }
558
+ process.exit(1);
559
+ }
560
+
561
+ if (uploadRes.status === 409) {
562
+ if (body.latestVersion) {
563
+ consola.error(`Version ${manifest.version} must be greater than ${body.latestVersion}`);
564
+ } else {
565
+ consola.error(body.error ?? "Version conflict");
566
+ }
567
+ process.exit(1);
568
+ }
569
+
570
+ if (uploadRes.status === 422 && body.audit) {
571
+ // Failed security audit
572
+ consola.error("Plugin failed security audit:");
573
+ consola.error(` Verdict: ${pc.red(body.audit.verdict)}`);
574
+ consola.error(` Summary: ${body.audit.summary}`);
575
+ process.exit(1);
576
+ }
577
+
578
+ consola.error(`Publish failed: ${body.error ?? uploadRes.statusText}`);
579
+ process.exit(1);
580
+ }
581
+
582
+ // ── Step 6: Handle response ──
583
+
584
+ const result = (await uploadRes.json()) as {
585
+ version: string;
586
+ bundleSize: number;
587
+ checksum: string;
588
+ publishedAt: string;
589
+ status?: string;
590
+ workflowId?: string;
591
+ audit?: {
592
+ verdict: string;
593
+ riskScore: number;
594
+ summary: string;
595
+ findings: { category: string; severity: string; description: string }[];
596
+ };
597
+ imageAudit?: {
598
+ verdict: string;
599
+ } | null;
600
+ };
601
+
602
+ console.log();
603
+ consola.success(`Uploaded ${pc.bold(`${manifest.id}@${result.version}`)}`);
604
+ consola.info(` Checksum: ${pc.dim(result.checksum)}`);
605
+ consola.info(` Size: ${(result.bundleSize / 1024).toFixed(1)}KB`);
606
+
607
+ // Async audit flow (202 Accepted)
608
+ if (uploadRes.status === 202) {
609
+ consola.info(` Status: ${pc.yellow("pending")} (audit running in background)`);
610
+
611
+ if (args["no-wait"]) {
612
+ consola.info("Skipping audit wait (--no-wait). Check status later.");
613
+ console.log();
614
+ return;
615
+ }
616
+
617
+ // Poll version endpoint for audit completion
618
+ consola.start("Waiting for security audit to complete...");
619
+ const versionUrl = new URL(
620
+ `/api/v1/plugins/${manifest.id}/versions/${manifest.version}`,
621
+ registryUrl,
622
+ );
623
+ const finalStatus = await pollVersionStatus(versionUrl.toString(), token);
624
+
625
+ if (finalStatus) {
626
+ displayAuditResults(finalStatus);
627
+ } else {
628
+ consola.warn("Audit did not complete within timeout. Check status later with:");
629
+ consola.info(` ${pc.dim(`curl ${versionUrl.toString()}`)}`);
630
+ }
631
+ } else {
632
+ // Synchronous response (201 or legacy)
633
+ if (result.audit) {
634
+ displayInlineAuditResults(result.audit, result.imageAudit ?? null);
635
+ }
636
+ consola.info(` Status: ${pc.green(result.status ?? "published")}`);
637
+ }
638
+
639
+ console.log();
640
+ },
641
+ });
642
+
643
+ // ── Marketplace auth subcommands ────────────────────────────────
644
+
645
+ export const marketplaceLoginCommand = defineCommand({
646
+ meta: {
647
+ name: "login",
648
+ description: "Log in to the EmDash Marketplace via GitHub",
649
+ },
650
+ args: {
651
+ registry: {
652
+ type: "string",
653
+ description: "Marketplace registry URL",
654
+ default: DEFAULT_REGISTRY,
655
+ },
656
+ },
657
+ async run({ args }) {
658
+ const registryUrl = args.registry;
659
+
660
+ const existing = getMarketplaceCredential(registryUrl);
661
+ if (existing) {
662
+ consola.info(`Already logged in as ${pc.bold(existing.author?.name ?? "unknown")}`);
663
+ consola.info("Use `emdash plugin logout` to log out first.");
664
+ return;
665
+ }
666
+
667
+ const result = await authenticateViaDeviceFlow(registryUrl);
668
+
669
+ saveMarketplaceCredential(registryUrl, {
670
+ token: result.token,
671
+ expiresAt: new Date(Date.now() + 30 * 86400 * 1000).toISOString(),
672
+ author: { id: result.author.id, name: result.author.name },
673
+ });
674
+
675
+ consola.success(`Logged in as ${pc.bold(result.author.name)}`);
676
+ },
677
+ });
678
+
679
+ export const marketplaceLogoutCommand = defineCommand({
680
+ meta: {
681
+ name: "logout",
682
+ description: "Log out of the EmDash Marketplace",
683
+ },
684
+ args: {
685
+ registry: {
686
+ type: "string",
687
+ description: "Marketplace registry URL",
688
+ default: DEFAULT_REGISTRY,
689
+ },
690
+ },
691
+ async run({ args }) {
692
+ const removed = removeMarketplaceCredential(args.registry);
693
+ if (removed) {
694
+ consola.success("Logged out of marketplace.");
695
+ } else {
696
+ consola.info("No marketplace credentials found.");
697
+ }
698
+ },
699
+ });