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.
- package/README.md +87 -1
- package/dist/adapters-BLMa4JGD.d.mts +106 -0
- package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
- package/dist/apply-Bjfq_b4-.mjs +1293 -0
- package/dist/apply-Bjfq_b4-.mjs.map +1 -0
- package/dist/astro/index.d.mts +51 -0
- package/dist/astro/index.d.mts.map +1 -0
- package/dist/astro/index.mjs +1333 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/middleware/auth.d.mts +31 -0
- package/dist/astro/middleware/auth.d.mts.map +1 -0
- package/dist/astro/middleware/auth.mjs +654 -0
- package/dist/astro/middleware/auth.mjs.map +1 -0
- package/dist/astro/middleware/redirect.d.mts +22 -0
- package/dist/astro/middleware/redirect.d.mts.map +1 -0
- package/dist/astro/middleware/redirect.mjs +63 -0
- package/dist/astro/middleware/redirect.mjs.map +1 -0
- package/dist/astro/middleware/request-context.d.mts +18 -0
- package/dist/astro/middleware/request-context.d.mts.map +1 -0
- package/dist/astro/middleware/request-context.mjs +1310 -0
- package/dist/astro/middleware/request-context.mjs.map +1 -0
- package/dist/astro/middleware/setup.d.mts +20 -0
- package/dist/astro/middleware/setup.d.mts.map +1 -0
- package/dist/astro/middleware/setup.mjs +47 -0
- package/dist/astro/middleware/setup.mjs.map +1 -0
- package/dist/astro/middleware.d.mts +13 -0
- package/dist/astro/middleware.d.mts.map +1 -0
- package/dist/astro/middleware.mjs +1613 -0
- package/dist/astro/middleware.mjs.map +1 -0
- package/dist/astro/types.d.mts +250 -0
- package/dist/astro/types.d.mts.map +1 -0
- package/dist/astro/types.mjs +1 -0
- package/dist/base64-MBPo9ozB.mjs +59 -0
- package/dist/base64-MBPo9ozB.mjs.map +1 -0
- package/dist/byline-CL847F26.mjs +213 -0
- package/dist/byline-CL847F26.mjs.map +1 -0
- package/dist/bylines-C2a-2TGt.mjs +136 -0
- package/dist/bylines-C2a-2TGt.mjs.map +1 -0
- package/dist/chunk-ClPoSABd.mjs +21 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +3909 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/cf-access.d.mts +60 -0
- package/dist/client/cf-access.d.mts.map +1 -0
- package/dist/client/cf-access.mjs +179 -0
- package/dist/client/cf-access.mjs.map +1 -0
- package/dist/client/index.d.mts +398 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +346 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/config-CKE8p9xM.mjs +55 -0
- package/dist/config-CKE8p9xM.mjs.map +1 -0
- package/dist/connection-B4zVnQIa.mjs +40 -0
- package/dist/connection-B4zVnQIa.mjs.map +1 -0
- package/dist/content-D6C2WsZC.mjs +824 -0
- package/dist/content-D6C2WsZC.mjs.map +1 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.mjs +62 -0
- package/dist/db/index.mjs.map +1 -0
- package/dist/db/libsql.d.mts +11 -0
- package/dist/db/libsql.d.mts.map +1 -0
- package/dist/db/libsql.mjs +17 -0
- package/dist/db/libsql.mjs.map +1 -0
- package/dist/db/postgres.d.mts +11 -0
- package/dist/db/postgres.d.mts.map +1 -0
- package/dist/db/postgres.mjs +30 -0
- package/dist/db/postgres.mjs.map +1 -0
- package/dist/db/sqlite.d.mts +11 -0
- package/dist/db/sqlite.d.mts.map +1 -0
- package/dist/db/sqlite.mjs +16 -0
- package/dist/db/sqlite.mjs.map +1 -0
- package/dist/default-Cyi4aAxu.mjs +81 -0
- package/dist/default-Cyi4aAxu.mjs.map +1 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
- package/dist/error-Cxz0tQeO.mjs +27 -0
- package/dist/error-Cxz0tQeO.mjs.map +1 -0
- package/dist/index-C1xF3OGh.d.mts +4527 -0
- package/dist/index-C1xF3OGh.d.mts.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +30 -0
- package/dist/load-yOOlckBj.mjs +28 -0
- package/dist/load-yOOlckBj.mjs.map +1 -0
- package/dist/loader-fz8Q_3EO.mjs +447 -0
- package/dist/loader-fz8Q_3EO.mjs.map +1 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
- package/dist/media/index.d.mts +26 -0
- package/dist/media/index.d.mts.map +1 -0
- package/dist/media/index.mjs +55 -0
- package/dist/media/index.mjs.map +1 -0
- package/dist/media/local-runtime.d.mts +39 -0
- package/dist/media/local-runtime.d.mts.map +1 -0
- package/dist/media/local-runtime.mjs +133 -0
- package/dist/media/local-runtime.mjs.map +1 -0
- package/dist/media-DqHVh136.mjs +200 -0
- package/dist/media-DqHVh136.mjs.map +1 -0
- package/dist/mode-C2EzN1uE.mjs +23 -0
- package/dist/mode-C2EzN1uE.mjs.map +1 -0
- package/dist/page/index.d.mts +140 -0
- package/dist/page/index.d.mts.map +1 -0
- package/dist/page/index.mjs +416 -0
- package/dist/page/index.mjs.map +1 -0
- package/dist/placeholder-CmGAmqeO.d.mts +276 -0
- package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
- package/dist/placeholder-SmpOx-_v.mjs +243 -0
- package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
- package/dist/plugin-utils.d.mts +58 -0
- package/dist/plugin-utils.d.mts.map +1 -0
- package/dist/plugin-utils.mjs +78 -0
- package/dist/plugin-utils.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
- package/dist/query-CS_iSj34.mjs +460 -0
- package/dist/query-CS_iSj34.mjs.map +1 -0
- package/dist/redirect-DIfIni3r.mjs +329 -0
- package/dist/redirect-DIfIni3r.mjs.map +1 -0
- package/dist/registry-D_w5HW4G.mjs +863 -0
- package/dist/registry-D_w5HW4G.mjs.map +1 -0
- package/dist/request-context.d.mts +49 -0
- package/dist/request-context.d.mts.map +1 -0
- package/dist/request-context.mjs +43 -0
- package/dist/request-context.mjs.map +1 -0
- package/dist/runner-B-u2F2b6.mjs +1412 -0
- package/dist/runner-B-u2F2b6.mjs.map +1 -0
- package/dist/runner-EAtf0ZIe.d.mts +27 -0
- package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
- package/dist/runtime.d.mts +26 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +42 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/search-DG603UrT.mjs +9211 -0
- package/dist/search-DG603UrT.mjs.map +1 -0
- package/dist/seed/index.d.mts +3 -0
- package/dist/seed/index.mjs +15 -0
- package/dist/seo/index.d.mts +70 -0
- package/dist/seo/index.d.mts.map +1 -0
- package/dist/seo/index.mjs +70 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/storage/local.d.mts +39 -0
- package/dist/storage/local.d.mts.map +1 -0
- package/dist/storage/local.mjs +166 -0
- package/dist/storage/local.mjs.map +1 -0
- package/dist/storage/s3.d.mts +32 -0
- package/dist/storage/s3.d.mts.map +1 -0
- package/dist/storage/s3.mjs +175 -0
- package/dist/storage/s3.mjs.map +1 -0
- package/dist/tokens-DpgrkrXK.mjs +171 -0
- package/dist/tokens-DpgrkrXK.mjs.map +1 -0
- package/dist/transport-BFGblqwG.d.mts +42 -0
- package/dist/transport-BFGblqwG.d.mts.map +1 -0
- package/dist/transport-yxiQsi8I.mjs +418 -0
- package/dist/transport-yxiQsi8I.mjs.map +1 -0
- package/dist/types-BRuPJGdV.d.mts +102 -0
- package/dist/types-BRuPJGdV.d.mts.map +1 -0
- package/dist/types-C4-fAxN3.d.mts +182 -0
- package/dist/types-C4-fAxN3.d.mts.map +1 -0
- package/dist/types-CMMN0pNg.mjs +31 -0
- package/dist/types-CMMN0pNg.mjs.map +1 -0
- package/dist/types-CUBbjgmP.mjs +16 -0
- package/dist/types-CUBbjgmP.mjs.map +1 -0
- package/dist/types-DRjfYOEv.d.mts +426 -0
- package/dist/types-DRjfYOEv.d.mts.map +1 -0
- package/dist/types-DY5zk5HN.mjs +73 -0
- package/dist/types-DY5zk5HN.mjs.map +1 -0
- package/dist/types-DaNLHo_T.d.mts +184 -0
- package/dist/types-DaNLHo_T.d.mts.map +1 -0
- package/dist/types-DvhsUmSJ.d.mts +1111 -0
- package/dist/types-DvhsUmSJ.d.mts.map +1 -0
- package/dist/validate-CpBtVMsD.d.mts +378 -0
- package/dist/validate-CpBtVMsD.d.mts.map +1 -0
- package/dist/validate-CqRJb_xU.mjs +97 -0
- package/dist/validate-CqRJb_xU.mjs.map +1 -0
- package/dist/validate-O7PWmlnq.mjs +328 -0
- package/dist/validate-O7PWmlnq.mjs.map +1 -0
- package/locals.d.ts +46 -0
- package/package.json +233 -19
- package/src/api/authorize.ts +63 -0
- package/src/api/csrf.ts +48 -0
- package/src/api/error.ts +99 -0
- package/src/api/errors.ts +445 -0
- package/src/api/escape.ts +9 -0
- package/src/api/handlers/api-tokens.ts +240 -0
- package/src/api/handlers/comments.ts +314 -0
- package/src/api/handlers/content.ts +1315 -0
- package/src/api/handlers/dashboard.ts +205 -0
- package/src/api/handlers/device-flow.ts +687 -0
- package/src/api/handlers/index.ts +163 -0
- package/src/api/handlers/manifest.ts +158 -0
- package/src/api/handlers/marketplace.ts +930 -0
- package/src/api/handlers/media.ts +207 -0
- package/src/api/handlers/menus.ts +493 -0
- package/src/api/handlers/oauth-authorization.ts +429 -0
- package/src/api/handlers/oauth-clients.ts +353 -0
- package/src/api/handlers/oauth-user-lookup.ts +39 -0
- package/src/api/handlers/plugins.ts +254 -0
- package/src/api/handlers/redirects.ts +360 -0
- package/src/api/handlers/revision.ts +145 -0
- package/src/api/handlers/schema.ts +534 -0
- package/src/api/handlers/sections.ts +289 -0
- package/src/api/handlers/seo.ts +115 -0
- package/src/api/handlers/settings.ts +49 -0
- package/src/api/handlers/snapshot.ts +350 -0
- package/src/api/handlers/taxonomies.ts +523 -0
- package/src/api/index.ts +6 -0
- package/src/api/openapi/document.ts +2368 -0
- package/src/api/openapi/index.ts +1 -0
- package/src/api/parse.ts +139 -0
- package/src/api/redirect.ts +14 -0
- package/src/api/rev.ts +67 -0
- package/src/api/schemas/auth.ts +112 -0
- package/src/api/schemas/bylines.ts +85 -0
- package/src/api/schemas/comments.ts +117 -0
- package/src/api/schemas/common.ts +89 -0
- package/src/api/schemas/content.ts +191 -0
- package/src/api/schemas/import.ts +52 -0
- package/src/api/schemas/index.ts +17 -0
- package/src/api/schemas/media.ts +116 -0
- package/src/api/schemas/menus.ts +111 -0
- package/src/api/schemas/redirects.ts +155 -0
- package/src/api/schemas/schema.ts +203 -0
- package/src/api/schemas/search.ts +63 -0
- package/src/api/schemas/sections.ts +67 -0
- package/src/api/schemas/settings.ts +63 -0
- package/src/api/schemas/setup.ts +37 -0
- package/src/api/schemas/taxonomies.ts +113 -0
- package/src/api/schemas/users.ts +96 -0
- package/src/api/schemas/widgets.ts +80 -0
- package/src/api/site-url.ts +25 -0
- package/src/api/types.ts +82 -0
- package/src/astro/index.ts +27 -0
- package/src/astro/integration/index.ts +303 -0
- package/src/astro/integration/routes.ts +834 -0
- package/src/astro/integration/runtime.ts +338 -0
- package/src/astro/integration/virtual-modules.ts +469 -0
- package/src/astro/integration/vite-config.ts +328 -0
- package/src/astro/middleware/auth.ts +743 -0
- package/src/astro/middleware/redirect.ts +89 -0
- package/src/astro/middleware/request-context.ts +129 -0
- package/src/astro/middleware/setup.ts +89 -0
- package/src/astro/middleware.ts +398 -0
- package/src/astro/routes/PluginRegistry.tsx +15 -0
- package/src/astro/routes/admin.astro +81 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +84 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +82 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +117 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
- package/src/astro/routes/api/auth/signup/complete.ts +85 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +105 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
- package/src/astro/routes/api/manifest.ts +62 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +190 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +412 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +51 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +55 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +53 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +100 -0
- package/src/astro/routes/api/setup/admin.ts +94 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +126 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +75 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +77 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +68 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +72 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +77 -0
- package/src/astro/routes/sitemap.xml.ts +97 -0
- package/src/astro/storage/adapters.ts +74 -0
- package/src/astro/storage/index.ts +19 -0
- package/src/astro/storage/types.ts +60 -0
- package/src/astro/types.ts +346 -0
- package/src/auth/api-tokens.ts +25 -0
- package/src/auth/challenge-store.ts +80 -0
- package/src/auth/mode.ts +96 -0
- package/src/auth/oauth-state-store.ts +96 -0
- package/src/auth/passkey-config.ts +27 -0
- package/src/auth/rate-limit.ts +158 -0
- package/src/auth/scopes.ts +33 -0
- package/src/auth/types.ts +104 -0
- package/src/aws-sdk.d.ts +100 -0
- package/src/bylines/index.ts +237 -0
- package/src/cleanup.ts +153 -0
- package/src/cli/client-factory.ts +100 -0
- package/src/cli/commands/auth.ts +46 -0
- package/src/cli/commands/bundle-utils.ts +247 -0
- package/src/cli/commands/bundle.ts +609 -0
- package/src/cli/commands/content.ts +442 -0
- package/src/cli/commands/dev.ts +191 -0
- package/src/cli/commands/doctor.ts +211 -0
- package/src/cli/commands/export-seed.ts +630 -0
- package/src/cli/commands/import/wordpress.ts +1056 -0
- package/src/cli/commands/init.ts +192 -0
- package/src/cli/commands/login.ts +547 -0
- package/src/cli/commands/media.ts +165 -0
- package/src/cli/commands/menu.ts +67 -0
- package/src/cli/commands/plugin-init.ts +291 -0
- package/src/cli/commands/plugin-validate.ts +31 -0
- package/src/cli/commands/plugin.ts +33 -0
- package/src/cli/commands/publish.ts +699 -0
- package/src/cli/commands/schema.ts +233 -0
- package/src/cli/commands/search-cmd.ts +54 -0
- package/src/cli/commands/seed.ts +288 -0
- package/src/cli/commands/taxonomy.ts +128 -0
- package/src/cli/commands/types.ts +68 -0
- package/src/cli/credentials.ts +236 -0
- package/src/cli/index.ts +70 -0
- package/src/cli/output.ts +75 -0
- package/src/cli/wxr/parser.ts +969 -0
- package/src/client/cf-access.ts +193 -0
- package/src/client/index.ts +854 -0
- package/src/client/portable-text.ts +413 -0
- package/src/client/transport.ts +200 -0
- package/src/comments/moderator.ts +46 -0
- package/src/comments/notifications.ts +144 -0
- package/src/comments/query.ts +105 -0
- package/src/comments/service.ts +213 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/EmDashBodyEnd.astro +32 -0
- package/src/components/EmDashBodyStart.astro +32 -0
- package/src/components/EmDashHead.astro +53 -0
- package/src/components/EmDashImage.astro +178 -0
- package/src/components/EmDashMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1905 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/content/converters/index.ts +9 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
- package/src/content/converters/types.ts +120 -0
- package/src/content/index.ts +5 -0
- package/src/database/connection.ts +67 -0
- package/src/database/dialect-helpers.ts +138 -0
- package/src/database/index.ts +5 -0
- package/src/database/migrations/001_initial.ts +136 -0
- package/src/database/migrations/002_media_status.ts +26 -0
- package/src/database/migrations/003_schema_registry.ts +79 -0
- package/src/database/migrations/004_plugins.ts +62 -0
- package/src/database/migrations/005_menus.ts +67 -0
- package/src/database/migrations/006_taxonomy_defs.ts +51 -0
- package/src/database/migrations/007_widgets.ts +42 -0
- package/src/database/migrations/008_auth.ts +194 -0
- package/src/database/migrations/009_user_disabled.ts +27 -0
- package/src/database/migrations/011_sections.ts +65 -0
- package/src/database/migrations/012_search.ts +25 -0
- package/src/database/migrations/013_scheduled_publishing.ts +51 -0
- package/src/database/migrations/014_draft_revisions.ts +72 -0
- package/src/database/migrations/015_indexes.ts +82 -0
- package/src/database/migrations/016_api_tokens.ts +89 -0
- package/src/database/migrations/017_authorization_codes.ts +45 -0
- package/src/database/migrations/018_seo.ts +56 -0
- package/src/database/migrations/019_i18n.ts +618 -0
- package/src/database/migrations/020_collection_url_pattern.ts +23 -0
- package/src/database/migrations/021_remove_section_categories.ts +43 -0
- package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
- package/src/database/migrations/023_plugin_metadata.ts +33 -0
- package/src/database/migrations/024_media_placeholders.ts +32 -0
- package/src/database/migrations/025_oauth_clients.ts +28 -0
- package/src/database/migrations/026_cron_tasks.ts +49 -0
- package/src/database/migrations/027_comments.ts +87 -0
- package/src/database/migrations/028_drop_author_url.ts +9 -0
- package/src/database/migrations/029_redirects.ts +67 -0
- package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
- package/src/database/migrations/031_bylines.ts +90 -0
- package/src/database/migrations/032_rate_limits.ts +42 -0
- package/src/database/migrations/runner.ts +170 -0
- package/src/database/repositories/audit.ts +294 -0
- package/src/database/repositories/byline.ts +387 -0
- package/src/database/repositories/comment.ts +458 -0
- package/src/database/repositories/content.ts +1144 -0
- package/src/database/repositories/index.ts +30 -0
- package/src/database/repositories/media.ts +347 -0
- package/src/database/repositories/options.ts +150 -0
- package/src/database/repositories/plugin-storage.ts +373 -0
- package/src/database/repositories/redirect.ts +480 -0
- package/src/database/repositories/revision.ts +200 -0
- package/src/database/repositories/seo.ts +176 -0
- package/src/database/repositories/taxonomy.ts +294 -0
- package/src/database/repositories/types.ts +132 -0
- package/src/database/repositories/user.ts +258 -0
- package/src/database/transaction.ts +54 -0
- package/src/database/types.ts +501 -0
- package/src/database/validate.ts +138 -0
- package/src/db/adapters.ts +125 -0
- package/src/db/index.ts +37 -0
- package/src/db/libsql.ts +23 -0
- package/src/db/postgres.ts +30 -0
- package/src/db/sqlite.ts +27 -0
- package/src/emdash-runtime.ts +2096 -0
- package/src/fields/boolean.ts +34 -0
- package/src/fields/datetime.ts +44 -0
- package/src/fields/file.ts +41 -0
- package/src/fields/image.ts +34 -0
- package/src/fields/index.ts +42 -0
- package/src/fields/integer.ts +50 -0
- package/src/fields/json.ts +37 -0
- package/src/fields/multiselect.ts +48 -0
- package/src/fields/number.ts +52 -0
- package/src/fields/portable-text.ts +33 -0
- package/src/fields/reference.ts +29 -0
- package/src/fields/richtext.ts +31 -0
- package/src/fields/select.ts +46 -0
- package/src/fields/slug.ts +38 -0
- package/src/fields/text.ts +55 -0
- package/src/fields/textarea.ts +52 -0
- package/src/fields/types.ts +64 -0
- package/src/i18n/config.ts +68 -0
- package/src/import/index.ts +90 -0
- package/src/import/menus.ts +436 -0
- package/src/import/registry.ts +111 -0
- package/src/import/sections.ts +103 -0
- package/src/import/settings.ts +281 -0
- package/src/import/sources/wordpress-plugin.ts +641 -0
- package/src/import/sources/wordpress-rest.ts +191 -0
- package/src/import/sources/wxr.ts +330 -0
- package/src/import/ssrf.ts +260 -0
- package/src/import/types.ts +418 -0
- package/src/import/utils.ts +412 -0
- package/src/index.ts +481 -0
- package/src/loader.ts +770 -0
- package/src/mcp/server.ts +1463 -0
- package/src/media/index.ts +32 -0
- package/src/media/local-runtime.ts +213 -0
- package/src/media/local.ts +46 -0
- package/src/media/normalize.ts +190 -0
- package/src/media/placeholder.ts +150 -0
- package/src/media/provider-loader.ts +78 -0
- package/src/media/types.ts +279 -0
- package/src/menus/index.ts +324 -0
- package/src/menus/types.ts +112 -0
- package/src/page/context.ts +93 -0
- package/src/page/fragments.ts +89 -0
- package/src/page/index.ts +58 -0
- package/src/page/jsonld.ts +94 -0
- package/src/page/metadata.ts +185 -0
- package/src/page/seo-contributions.ts +136 -0
- package/src/plugin-utils.ts +80 -0
- package/src/plugins/adapt-sandbox-entry.ts +207 -0
- package/src/plugins/context.ts +833 -0
- package/src/plugins/cron.ts +361 -0
- package/src/plugins/define-plugin.ts +259 -0
- package/src/plugins/email-console.ts +73 -0
- package/src/plugins/email.ts +209 -0
- package/src/plugins/hooks.ts +1273 -0
- package/src/plugins/index.ts +193 -0
- package/src/plugins/manager.ts +595 -0
- package/src/plugins/manifest-schema.ts +230 -0
- package/src/plugins/marketplace.ts +460 -0
- package/src/plugins/request-meta.ts +139 -0
- package/src/plugins/routes.ts +302 -0
- package/src/plugins/sandbox/index.ts +18 -0
- package/src/plugins/sandbox/noop.ts +76 -0
- package/src/plugins/sandbox/types.ts +173 -0
- package/src/plugins/scheduler/node.ts +122 -0
- package/src/plugins/scheduler/piggyback.ts +71 -0
- package/src/plugins/scheduler/types.ts +27 -0
- package/src/plugins/state.ts +208 -0
- package/src/plugins/storage-indexes.ts +326 -0
- package/src/plugins/storage-query.ts +240 -0
- package/src/plugins/types.ts +1284 -0
- package/src/preview/helpers.ts +27 -0
- package/src/preview/index.ts +40 -0
- package/src/preview/tokens.ts +279 -0
- package/src/preview/urls.ts +118 -0
- package/src/query.ts +674 -0
- package/src/redirects/patterns.ts +224 -0
- package/src/request-context.ts +67 -0
- package/src/runtime.ts +21 -0
- package/src/schema/index.ts +29 -0
- package/src/schema/query.ts +44 -0
- package/src/schema/registry.ts +965 -0
- package/src/schema/types.ts +276 -0
- package/src/schema/zod-generator.ts +413 -0
- package/src/search/fts-manager.ts +452 -0
- package/src/search/index.ts +26 -0
- package/src/search/query.ts +396 -0
- package/src/search/text-extraction.ts +162 -0
- package/src/search/types.ts +114 -0
- package/src/sections/index.ts +226 -0
- package/src/sections/types.ts +86 -0
- package/src/seed/apply.ts +1141 -0
- package/src/seed/default.ts +86 -0
- package/src/seed/index.ts +28 -0
- package/src/seed/load.ts +35 -0
- package/src/seed/types.ts +341 -0
- package/src/seed/validate.ts +642 -0
- package/src/seo/index.ts +179 -0
- package/src/settings/index.ts +203 -0
- package/src/settings/types.ts +58 -0
- package/src/storage/index.ts +28 -0
- package/src/storage/local.ts +253 -0
- package/src/storage/s3.ts +271 -0
- package/src/storage/types.ts +204 -0
- package/src/taxonomies/index.ts +309 -0
- package/src/taxonomies/types.ts +61 -0
- package/src/ui.ts +75 -0
- package/src/utils/base64.ts +73 -0
- package/src/utils/hash.ts +36 -0
- package/src/utils/sanitize.ts +20 -0
- package/src/utils/slugify.ts +29 -0
- package/src/utils/url.ts +48 -0
- package/src/virtual-modules.d.ts +111 -0
- package/src/visual-editing/editable.ts +108 -0
- package/src/visual-editing/toolbar.ts +1229 -0
- package/src/widgets/components.ts +105 -0
- package/src/widgets/index.ts +131 -0
- 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
|
+
});
|