emdash 0.0.0-b → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -43
- 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 +1336 -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-C0hCbYnD.mjs +1412 -0
- package/dist/runner-C0hCbYnD.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 +684 -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 +349 -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 +335 -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 +116 -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 +115 -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 +101 -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 +58 -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 +68 -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 +697 -0
- package/src/cli/commands/schema.ts +233 -0
- package/src/cli/commands/search-cmd.ts +54 -0
- package/src/cli/commands/seed.ts +286 -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 +170 -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 +39 -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 +249 -0
- package/src/storage/s3.ts +263 -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,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress Application Password OAuth callback
|
|
3
|
+
*
|
|
4
|
+
* GET /_emdash/api/import/wordpress-plugin/callback
|
|
5
|
+
*
|
|
6
|
+
* WordPress redirects here after user approves the application password.
|
|
7
|
+
* We receive the credentials and redirect to the admin import UI with a token.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { APIRoute } from "astro";
|
|
11
|
+
|
|
12
|
+
import { encodeBase64 } from "#utils/base64.js";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
export const GET: APIRoute = async ({ url, cookies, redirect }) => {
|
|
17
|
+
// WordPress sends these params on success:
|
|
18
|
+
// - site_url: The WordPress site URL
|
|
19
|
+
// - user_login: The username
|
|
20
|
+
// - password: The newly created application password
|
|
21
|
+
//
|
|
22
|
+
// On rejection, it redirects to reject_url (if provided) or just doesn't include credentials
|
|
23
|
+
|
|
24
|
+
const siteUrl = url.searchParams.get("site_url");
|
|
25
|
+
const userLogin = url.searchParams.get("user_login");
|
|
26
|
+
const password = url.searchParams.get("password");
|
|
27
|
+
|
|
28
|
+
// Check if this is a rejection (no credentials)
|
|
29
|
+
if (!siteUrl || !userLogin || !password) {
|
|
30
|
+
return redirect("/_emdash/admin/import/wordpress?error=auth_rejected");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create the Basic Auth token
|
|
34
|
+
const token = encodeBase64(`${userLogin}:${password}`);
|
|
35
|
+
|
|
36
|
+
// Store credentials in a short-lived cookie (5 minutes)
|
|
37
|
+
// This allows the import UI to retrieve them
|
|
38
|
+
const authData = JSON.stringify({
|
|
39
|
+
siteUrl,
|
|
40
|
+
userLogin,
|
|
41
|
+
token,
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Base64 encode the auth data for cookie storage
|
|
46
|
+
const encodedAuth = encodeBase64(authData);
|
|
47
|
+
|
|
48
|
+
cookies.set("emdash_wp_auth", encodedAuth, {
|
|
49
|
+
path: "/_emdash/",
|
|
50
|
+
maxAge: 300, // 5 minutes
|
|
51
|
+
httpOnly: false, // Needs to be readable by JS
|
|
52
|
+
secure: url.protocol === "https:",
|
|
53
|
+
sameSite: "lax",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Redirect to import UI - it will pick up the cookie
|
|
57
|
+
return redirect("/_emdash/admin/import/wordpress?auth=success");
|
|
58
|
+
};
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress Plugin execute import endpoint
|
|
3
|
+
*
|
|
4
|
+
* POST /_emdash/api/import/wordpress-plugin/execute
|
|
5
|
+
*
|
|
6
|
+
* Imports content from WordPress via EmDash Exporter plugin API.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { APIRoute } from "astro";
|
|
10
|
+
import { ContentRepository, SchemaRegistry } from "emdash";
|
|
11
|
+
|
|
12
|
+
import { requirePerm } from "#api/authorize.js";
|
|
13
|
+
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
14
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
15
|
+
import { wpPluginExecuteBody } from "#api/schemas.js";
|
|
16
|
+
import { BylineRepository } from "#db/repositories/byline.js";
|
|
17
|
+
import { getSource } from "#import/index.js";
|
|
18
|
+
import { validateExternalUrl, SsrfError } from "#import/ssrf.js";
|
|
19
|
+
import type { ImportConfig, ImportResult, NormalizedItem } from "#import/types.js";
|
|
20
|
+
import { resolveImportByline } from "#import/utils.js";
|
|
21
|
+
import type { FieldType } from "#schema/types.js";
|
|
22
|
+
import type { EmDashHandlers, EmDashManifest } from "#types";
|
|
23
|
+
import { slugify } from "#utils/slugify.js";
|
|
24
|
+
|
|
25
|
+
export const prerender = false;
|
|
26
|
+
|
|
27
|
+
export interface WpPluginImportConfig extends ImportConfig {
|
|
28
|
+
/** Author mappings (WP author login -> EmDash user ID) */
|
|
29
|
+
authorMappings?: Record<string, string | null>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface WpPluginImportResponse {
|
|
33
|
+
success: boolean;
|
|
34
|
+
result?: ImportResult;
|
|
35
|
+
error?: { message: string };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
39
|
+
const { emdash, emdashManifest, user } = locals;
|
|
40
|
+
|
|
41
|
+
const denied = requirePerm(user, "import:execute");
|
|
42
|
+
if (denied) return denied;
|
|
43
|
+
|
|
44
|
+
if (!emdash?.handleContentCreate) {
|
|
45
|
+
return apiError("NOT_CONFIGURED", "EmDash not configured", 500);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const body = await parseBody(request, wpPluginExecuteBody);
|
|
50
|
+
if (isParseError(body)) return body;
|
|
51
|
+
|
|
52
|
+
// SSRF: reject internal/private network targets
|
|
53
|
+
try {
|
|
54
|
+
validateExternalUrl(body.url);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
const msg = e instanceof SsrfError ? e.message : "Invalid URL";
|
|
57
|
+
return apiError("SSRF_BLOCKED", msg, 400);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Zod schema output narrowed to WpPluginImportConfig
|
|
61
|
+
const config = body.config as unknown as WpPluginImportConfig;
|
|
62
|
+
|
|
63
|
+
// Get the WordPress plugin source
|
|
64
|
+
const source = getSource("wordpress-plugin");
|
|
65
|
+
if (!source) {
|
|
66
|
+
return apiError("NOT_CONFIGURED", "WordPress plugin source not available", 500);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Build the list of post types to fetch
|
|
70
|
+
const postTypes = Object.entries(config.postTypeMappings)
|
|
71
|
+
.filter(([_, mapping]) => mapping.enabled)
|
|
72
|
+
.map(([postType]) => postType);
|
|
73
|
+
|
|
74
|
+
if (postTypes.length === 0) {
|
|
75
|
+
return apiError("VALIDATION_ERROR", "No post types selected for import", 400);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log("[WP Plugin Import] Starting import for:", body.url);
|
|
79
|
+
console.log("[WP Plugin Import] Post types:", postTypes);
|
|
80
|
+
|
|
81
|
+
// Import content (including drafts since we have auth)
|
|
82
|
+
const result = await importContent(
|
|
83
|
+
source.fetchContent(
|
|
84
|
+
{ type: "url", url: body.url, token: body.token },
|
|
85
|
+
{ postTypes, includeDrafts: true },
|
|
86
|
+
),
|
|
87
|
+
config,
|
|
88
|
+
emdash,
|
|
89
|
+
emdashManifest,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
console.log("[WP Plugin Import] Import result:", JSON.stringify(result, null, 2));
|
|
93
|
+
|
|
94
|
+
return apiSuccess({
|
|
95
|
+
success: true,
|
|
96
|
+
result,
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
return handleError(error, "Failed to import from WordPress", "WP_PLUGIN_IMPORT_ERROR");
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/** Fields that should be auto-created if they don't exist */
|
|
104
|
+
const IMPORT_FIELDS: Array<{
|
|
105
|
+
slug: string;
|
|
106
|
+
label: string;
|
|
107
|
+
type: FieldType;
|
|
108
|
+
check: (item: NormalizedItem) => boolean;
|
|
109
|
+
}> = [
|
|
110
|
+
{
|
|
111
|
+
slug: "title",
|
|
112
|
+
label: "Title",
|
|
113
|
+
type: "string",
|
|
114
|
+
check: () => true,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
slug: "content",
|
|
118
|
+
label: "Content",
|
|
119
|
+
type: "portableText",
|
|
120
|
+
check: () => true,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
slug: "excerpt",
|
|
124
|
+
label: "Excerpt",
|
|
125
|
+
type: "text",
|
|
126
|
+
check: (item) => !!item.excerpt,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
slug: "featured_image",
|
|
130
|
+
label: "Featured Image",
|
|
131
|
+
type: "image",
|
|
132
|
+
check: (item) => !!item.featuredImage,
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
async function importContent(
|
|
137
|
+
items: AsyncGenerator<NormalizedItem>,
|
|
138
|
+
config: WpPluginImportConfig,
|
|
139
|
+
emdash: EmDashHandlers,
|
|
140
|
+
manifest: EmDashManifest,
|
|
141
|
+
): Promise<ImportResult> {
|
|
142
|
+
const result: ImportResult = {
|
|
143
|
+
success: true,
|
|
144
|
+
imported: 0,
|
|
145
|
+
skipped: 0,
|
|
146
|
+
errors: [],
|
|
147
|
+
byCollection: {},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Create content repository for checking existing items
|
|
151
|
+
const contentRepo = new ContentRepository(emdash.db);
|
|
152
|
+
const bylineRepo = new BylineRepository(emdash.db);
|
|
153
|
+
const bylineCache = new Map<string, string>();
|
|
154
|
+
const schemaRegistry = new SchemaRegistry(emdash.db);
|
|
155
|
+
|
|
156
|
+
// Track which collections have had fields ensured
|
|
157
|
+
const ensuredCollections = new Set<string>();
|
|
158
|
+
|
|
159
|
+
// Track source translationGroup -> EmDash item ID for translation linking.
|
|
160
|
+
// Maps source-side translation group ID to the EmDash ID of the first item
|
|
161
|
+
// imported for that group (the default-locale item).
|
|
162
|
+
const translationGroupMap = new Map<string, string>();
|
|
163
|
+
|
|
164
|
+
for await (const item of items) {
|
|
165
|
+
console.log("[WP Plugin Import] Processing item:", {
|
|
166
|
+
sourceId: item.sourceId,
|
|
167
|
+
title: item.title,
|
|
168
|
+
postType: item.postType,
|
|
169
|
+
status: item.status,
|
|
170
|
+
contentBlocks: Array.isArray(item.content) ? item.content.length : 0,
|
|
171
|
+
featuredImage: item.featuredImage,
|
|
172
|
+
locale: item.locale,
|
|
173
|
+
translationGroup: item.translationGroup,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const mapping = config.postTypeMappings[item.postType];
|
|
177
|
+
|
|
178
|
+
// Skip if not mapped or disabled
|
|
179
|
+
if (!mapping || !mapping.enabled) {
|
|
180
|
+
result.skipped++;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const collection = mapping.collection;
|
|
185
|
+
|
|
186
|
+
// Check if collection exists in manifest
|
|
187
|
+
if (!manifest?.collections[collection]) {
|
|
188
|
+
result.errors.push({
|
|
189
|
+
title: item.title || "Untitled",
|
|
190
|
+
error: `Collection "${collection}" does not exist`,
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
// Ensure required fields exist in the collection schema (once per collection)
|
|
197
|
+
if (!ensuredCollections.has(collection)) {
|
|
198
|
+
for (const field of IMPORT_FIELDS) {
|
|
199
|
+
if (field.check(item)) {
|
|
200
|
+
const existingField = await schemaRegistry.getField(collection, field.slug);
|
|
201
|
+
if (!existingField) {
|
|
202
|
+
console.log(
|
|
203
|
+
`[WP Plugin Import] Creating missing field "${field.slug}" in collection "${collection}"`,
|
|
204
|
+
);
|
|
205
|
+
try {
|
|
206
|
+
await schemaRegistry.createField(collection, {
|
|
207
|
+
slug: field.slug,
|
|
208
|
+
label: field.label,
|
|
209
|
+
type: field.type,
|
|
210
|
+
required: false,
|
|
211
|
+
});
|
|
212
|
+
} catch (e) {
|
|
213
|
+
// Field might already exist from concurrent creation
|
|
214
|
+
console.log(
|
|
215
|
+
`[WP Plugin Import] Field "${field.slug}" creation skipped:`,
|
|
216
|
+
e instanceof Error ? e.message : e,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
ensuredCollections.add(collection);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Generate slug from item slug or title
|
|
226
|
+
const slug = item.slug || slugify(item.title || `post-${item.sourceId}`);
|
|
227
|
+
|
|
228
|
+
// Check if already exists (idempotency) — locale-aware lookup
|
|
229
|
+
if (config.skipExisting) {
|
|
230
|
+
const existing = await contentRepo.findBySlug(collection, slug, item.locale);
|
|
231
|
+
if (existing) {
|
|
232
|
+
// Still track the translation group mapping for later items
|
|
233
|
+
if (item.translationGroup) {
|
|
234
|
+
translationGroupMap.set(item.translationGroup, existing.id);
|
|
235
|
+
}
|
|
236
|
+
result.skipped++;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Map WordPress status to EmDash status
|
|
242
|
+
const status = mapStatus(item.status);
|
|
243
|
+
|
|
244
|
+
// Build data object - add all applicable fields
|
|
245
|
+
const data: Record<string, unknown> = {};
|
|
246
|
+
|
|
247
|
+
// Add standard fields
|
|
248
|
+
data.title = item.title || "Untitled";
|
|
249
|
+
data.content = item.content;
|
|
250
|
+
|
|
251
|
+
if (item.excerpt) {
|
|
252
|
+
data.excerpt = item.excerpt;
|
|
253
|
+
}
|
|
254
|
+
if (item.featuredImage) {
|
|
255
|
+
data.featured_image = item.featuredImage;
|
|
256
|
+
console.log("[WP Plugin Import] Adding featured_image:", item.featuredImage);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Note: ACF/Yoast/RankMath fields are not added automatically
|
|
260
|
+
// They would need matching fields in the EmDash schema
|
|
261
|
+
|
|
262
|
+
// Resolve author ID from mappings
|
|
263
|
+
let authorId: string | undefined;
|
|
264
|
+
if (config.authorMappings && item.author) {
|
|
265
|
+
const mappedUserId = config.authorMappings[item.author];
|
|
266
|
+
if (mappedUserId !== undefined && mappedUserId !== null) {
|
|
267
|
+
authorId = mappedUserId;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const bylineId = await resolveImportByline(
|
|
272
|
+
item.author,
|
|
273
|
+
item.author, // display name fallback is the login
|
|
274
|
+
authorId,
|
|
275
|
+
bylineRepo,
|
|
276
|
+
bylineCache,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// Resolve translation link: if this item has a translationGroup and
|
|
280
|
+
// we've already imported another item in the same group, link them.
|
|
281
|
+
let translationOf: string | undefined;
|
|
282
|
+
if (item.translationGroup) {
|
|
283
|
+
const existingGroupItem = translationGroupMap.get(item.translationGroup);
|
|
284
|
+
if (existingGroupItem) {
|
|
285
|
+
translationOf = existingGroupItem;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Create the content item
|
|
290
|
+
const createResult = await emdash.handleContentCreate(collection, {
|
|
291
|
+
data,
|
|
292
|
+
slug,
|
|
293
|
+
status,
|
|
294
|
+
authorId,
|
|
295
|
+
bylines: bylineId ? [{ bylineId }] : undefined,
|
|
296
|
+
locale: item.locale,
|
|
297
|
+
translationOf,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
if (createResult.success) {
|
|
301
|
+
result.imported++;
|
|
302
|
+
result.byCollection[collection] = (result.byCollection[collection] || 0) + 1;
|
|
303
|
+
|
|
304
|
+
// Track translation group: first item in a group establishes the mapping
|
|
305
|
+
if (item.translationGroup && !translationGroupMap.has(item.translationGroup)) {
|
|
306
|
+
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler success data includes id
|
|
307
|
+
const createdData = createResult.data as { id?: string } | undefined;
|
|
308
|
+
if (createdData?.id) {
|
|
309
|
+
translationGroupMap.set(item.translationGroup, createdData.id);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
result.errors.push({
|
|
314
|
+
title: item.title || "Untitled",
|
|
315
|
+
error:
|
|
316
|
+
typeof createResult.error === "object" && createResult.error !== null
|
|
317
|
+
? (createResult.error as { message?: string }).message || "Unknown error"
|
|
318
|
+
: String(createResult.error),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error(`Import error for "${item.title || "Untitled"}":`, error);
|
|
323
|
+
result.errors.push({
|
|
324
|
+
title: item.title || "Untitled",
|
|
325
|
+
error: "Failed to import item",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
result.success = result.errors.length === 0;
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function mapStatus(wpStatus: string | undefined): string {
|
|
335
|
+
switch (wpStatus) {
|
|
336
|
+
case "publish":
|
|
337
|
+
return "published";
|
|
338
|
+
case "draft":
|
|
339
|
+
return "draft";
|
|
340
|
+
case "pending":
|
|
341
|
+
return "draft";
|
|
342
|
+
case "private":
|
|
343
|
+
return "draft";
|
|
344
|
+
default:
|
|
345
|
+
return "draft";
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin manifest endpoint - injected by EmDash integration
|
|
3
|
+
*
|
|
4
|
+
* GET /_emdash/api/manifest
|
|
5
|
+
*
|
|
6
|
+
* Returns the admin manifest with collection definitions and plugin info.
|
|
7
|
+
* The manifest is generated from the user's live.config.ts at runtime.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { APIRoute } from "astro";
|
|
11
|
+
|
|
12
|
+
import { getAuthMode } from "#auth/mode.js";
|
|
13
|
+
|
|
14
|
+
import type { EmDashManifest } from "../../types.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const GET: APIRoute = async ({ locals }) => {
|
|
19
|
+
const { emdashManifest, emdash } = locals;
|
|
20
|
+
|
|
21
|
+
// Determine auth mode from config
|
|
22
|
+
const authMode = getAuthMode(emdash?.config);
|
|
23
|
+
|
|
24
|
+
// Check if self-signup is enabled (any allowed domain with enabled = 1)
|
|
25
|
+
// Only relevant for passkey auth — external auth providers handle their own signup
|
|
26
|
+
let signupEnabled = false;
|
|
27
|
+
if (emdash?.db && authMode.type === "passkey") {
|
|
28
|
+
try {
|
|
29
|
+
const { sql } = await import("kysely");
|
|
30
|
+
const result = await sql<{ cnt: unknown }>`
|
|
31
|
+
SELECT COUNT(*) as cnt FROM allowed_domains WHERE enabled = 1
|
|
32
|
+
`.execute(emdash.db);
|
|
33
|
+
signupEnabled = Number(result.rows[0]?.cnt ?? 0) > 0;
|
|
34
|
+
} catch {
|
|
35
|
+
// Table may not exist yet, that's fine
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const manifest: EmDashManifest = emdashManifest
|
|
40
|
+
? {
|
|
41
|
+
...emdashManifest,
|
|
42
|
+
authMode: authMode.type === "external" ? authMode.providerType : "passkey",
|
|
43
|
+
signupEnabled,
|
|
44
|
+
}
|
|
45
|
+
: {
|
|
46
|
+
version: "0.1.0",
|
|
47
|
+
hash: "default",
|
|
48
|
+
collections: {},
|
|
49
|
+
plugins: {},
|
|
50
|
+
authMode: "passkey",
|
|
51
|
+
signupEnabled,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return Response.json(
|
|
55
|
+
{ data: manifest },
|
|
56
|
+
{
|
|
57
|
+
headers: {
|
|
58
|
+
"Cache-Control": "private, no-store",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Streamable HTTP endpoint
|
|
3
|
+
*
|
|
4
|
+
* Exposes an MCP server at /_emdash/api/mcp using the Streamable HTTP
|
|
5
|
+
* transport (Web Standard variant). The server runs stateless — each
|
|
6
|
+
* request creates a fresh transport, so no session tracking is needed.
|
|
7
|
+
* Authentication is handled by the existing EmDash auth middleware.
|
|
8
|
+
*
|
|
9
|
+
* POST /_emdash/api/mcp — JSON-RPC tool calls
|
|
10
|
+
* GET /_emdash/api/mcp — SSE stream (not used in stateless mode)
|
|
11
|
+
* DELETE /_emdash/api/mcp — Session close (not used in stateless mode)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
15
|
+
import type { APIRoute } from "astro";
|
|
16
|
+
|
|
17
|
+
import { apiError } from "#api/error.js";
|
|
18
|
+
import { createMcpServer } from "#mcp/server.js";
|
|
19
|
+
|
|
20
|
+
export const prerender = false;
|
|
21
|
+
|
|
22
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
23
|
+
const { emdash, user } = locals;
|
|
24
|
+
|
|
25
|
+
if (!emdash) {
|
|
26
|
+
return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!user) {
|
|
30
|
+
return apiError("UNAUTHORIZED", "Authentication required", 401);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const server = createMcpServer();
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
37
|
+
// Stateless: no session management
|
|
38
|
+
sessionIdGenerator: undefined,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await server.connect(transport);
|
|
42
|
+
|
|
43
|
+
return await transport.handleRequest(request, {
|
|
44
|
+
authInfo: {
|
|
45
|
+
token: "",
|
|
46
|
+
clientId: "emdash-admin",
|
|
47
|
+
scopes: [],
|
|
48
|
+
extra: {
|
|
49
|
+
emdash,
|
|
50
|
+
userId: user.id,
|
|
51
|
+
userRole: user.role,
|
|
52
|
+
tokenScopes: locals.tokenScopes,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error("[MCP]", error);
|
|
58
|
+
await server.close().catch(() => {});
|
|
59
|
+
|
|
60
|
+
return new Response(
|
|
61
|
+
JSON.stringify({
|
|
62
|
+
jsonrpc: "2.0",
|
|
63
|
+
error: {
|
|
64
|
+
code: -32603,
|
|
65
|
+
message: "Internal server error",
|
|
66
|
+
},
|
|
67
|
+
id: null,
|
|
68
|
+
}),
|
|
69
|
+
{
|
|
70
|
+
status: 500,
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
"Cache-Control": "private, no-store",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* GET — SSE stream. Not used in stateless mode.
|
|
82
|
+
*/
|
|
83
|
+
export const GET: APIRoute = async () => {
|
|
84
|
+
return new Response(
|
|
85
|
+
JSON.stringify({
|
|
86
|
+
jsonrpc: "2.0",
|
|
87
|
+
error: {
|
|
88
|
+
code: -32000,
|
|
89
|
+
message: "Method not allowed. This is a stateless MCP endpoint — use POST.",
|
|
90
|
+
},
|
|
91
|
+
id: null,
|
|
92
|
+
}),
|
|
93
|
+
{
|
|
94
|
+
status: 405,
|
|
95
|
+
headers: {
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
"Cache-Control": "private, no-store",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* DELETE — Session close. Not used in stateless mode.
|
|
105
|
+
*/
|
|
106
|
+
export const DELETE: APIRoute = async () => {
|
|
107
|
+
return new Response(
|
|
108
|
+
JSON.stringify({
|
|
109
|
+
jsonrpc: "2.0",
|
|
110
|
+
error: {
|
|
111
|
+
code: -32000,
|
|
112
|
+
message: "Method not allowed. This is a stateless MCP endpoint.",
|
|
113
|
+
},
|
|
114
|
+
id: null,
|
|
115
|
+
}),
|
|
116
|
+
{
|
|
117
|
+
status: 405,
|
|
118
|
+
headers: {
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"Cache-Control": "private, no-store",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirm media upload endpoint
|
|
3
|
+
*
|
|
4
|
+
* POST /_emdash/api/media/{id}/confirm
|
|
5
|
+
*
|
|
6
|
+
* Confirms that the client has successfully uploaded the file to storage.
|
|
7
|
+
* Marks the media record as ready and optionally updates metadata.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { APIRoute } from "astro";
|
|
11
|
+
import { MediaRepository } from "emdash";
|
|
12
|
+
|
|
13
|
+
import { requirePerm } from "#api/authorize.js";
|
|
14
|
+
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
15
|
+
import { isParseError, parseOptionalBody } from "#api/parse.js";
|
|
16
|
+
import { mediaConfirmBody } from "#api/schemas.js";
|
|
17
|
+
import type { MediaItem } from "#types";
|
|
18
|
+
|
|
19
|
+
export const prerender = false;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add URL to media item (relative URL for portability)
|
|
23
|
+
*/
|
|
24
|
+
function addUrlToMedia(item: MediaItem): MediaItem & { url: string } {
|
|
25
|
+
return {
|
|
26
|
+
...item,
|
|
27
|
+
url: `/_emdash/api/media/file/${item.storageKey}`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Confirm upload completion
|
|
33
|
+
*/
|
|
34
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
35
|
+
const { emdash, user } = locals;
|
|
36
|
+
const { id } = params;
|
|
37
|
+
|
|
38
|
+
const denied = requirePerm(user, "media:upload");
|
|
39
|
+
if (denied) return denied;
|
|
40
|
+
|
|
41
|
+
if (!id) {
|
|
42
|
+
return apiError("INVALID_REQUEST", "Media ID is required", 400);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!emdash?.db) {
|
|
46
|
+
return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const body = await parseOptionalBody(request, mediaConfirmBody, {});
|
|
51
|
+
if (isParseError(body)) return body;
|
|
52
|
+
|
|
53
|
+
const repo = new MediaRepository(emdash.db);
|
|
54
|
+
|
|
55
|
+
// Get the media item first to check status
|
|
56
|
+
const existing = await repo.findById(id);
|
|
57
|
+
if (!existing) {
|
|
58
|
+
return apiError("NOT_FOUND", `Media item not found: ${id}`, 404);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (existing.status !== "pending") {
|
|
62
|
+
return apiError("INVALID_STATE", `Media item is not pending: ${existing.status}`, 400);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Optionally verify the file exists in storage
|
|
66
|
+
if (emdash.storage) {
|
|
67
|
+
const exists = await emdash.storage.exists(existing.storageKey);
|
|
68
|
+
if (!exists) {
|
|
69
|
+
// Mark as failed
|
|
70
|
+
await repo.markFailed(id);
|
|
71
|
+
return apiError("FILE_NOT_FOUND", "File was not uploaded to storage", 400);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Confirm the upload
|
|
76
|
+
const item = await repo.confirmUpload(id, {
|
|
77
|
+
size: body.size,
|
|
78
|
+
width: body.width,
|
|
79
|
+
height: body.height,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (!item) {
|
|
83
|
+
return apiError("CONFIRM_FAILED", "Failed to confirm upload", 500);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add URL to the response (relative URL for portability)
|
|
87
|
+
const itemWithUrl = addUrlToMedia(item);
|
|
88
|
+
|
|
89
|
+
return apiSuccess({ item: itemWithUrl });
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return handleError(error, "Failed to confirm upload", "CONFIRM_ERROR");
|
|
92
|
+
}
|
|
93
|
+
};
|