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,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime API for taxonomies
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to query taxonomy definitions and terms.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getDb } from "../loader.js";
|
|
8
|
+
import type { TaxonomyDef, TaxonomyTerm, TaxonomyTermRow } from "./types.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get all taxonomy definitions
|
|
12
|
+
*/
|
|
13
|
+
export async function getTaxonomyDefs(): Promise<TaxonomyDef[]> {
|
|
14
|
+
const db = await getDb();
|
|
15
|
+
|
|
16
|
+
const rows = await db.selectFrom("_emdash_taxonomy_defs").selectAll().execute();
|
|
17
|
+
|
|
18
|
+
return rows.map((row) => ({
|
|
19
|
+
id: row.id,
|
|
20
|
+
name: row.name,
|
|
21
|
+
label: row.label,
|
|
22
|
+
labelSingular: row.label_singular ?? undefined,
|
|
23
|
+
hierarchical: row.hierarchical === 1,
|
|
24
|
+
collections: row.collections ? JSON.parse(row.collections) : [],
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get a single taxonomy definition by name
|
|
30
|
+
*/
|
|
31
|
+
export async function getTaxonomyDef(name: string): Promise<TaxonomyDef | null> {
|
|
32
|
+
const db = await getDb();
|
|
33
|
+
|
|
34
|
+
const row = await db
|
|
35
|
+
.selectFrom("_emdash_taxonomy_defs")
|
|
36
|
+
.selectAll()
|
|
37
|
+
.where("name", "=", name)
|
|
38
|
+
.executeTakeFirst();
|
|
39
|
+
|
|
40
|
+
if (!row) return null;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
id: row.id,
|
|
44
|
+
name: row.name,
|
|
45
|
+
label: row.label,
|
|
46
|
+
labelSingular: row.label_singular ?? undefined,
|
|
47
|
+
hierarchical: row.hierarchical === 1,
|
|
48
|
+
collections: row.collections ? JSON.parse(row.collections) : [],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
|
|
54
|
+
*/
|
|
55
|
+
export async function getTaxonomyTerms(taxonomyName: string): Promise<TaxonomyTerm[]> {
|
|
56
|
+
const db = await getDb();
|
|
57
|
+
|
|
58
|
+
// Get taxonomy definition to check if hierarchical
|
|
59
|
+
const def = await getTaxonomyDef(taxonomyName);
|
|
60
|
+
if (!def) return [];
|
|
61
|
+
|
|
62
|
+
// Get all terms for this taxonomy
|
|
63
|
+
const rows = await db
|
|
64
|
+
.selectFrom("taxonomies")
|
|
65
|
+
.selectAll()
|
|
66
|
+
.where("name", "=", taxonomyName)
|
|
67
|
+
.orderBy("label", "asc")
|
|
68
|
+
.execute();
|
|
69
|
+
|
|
70
|
+
// Count entries for each term
|
|
71
|
+
const countsResult = await db
|
|
72
|
+
.selectFrom("content_taxonomies")
|
|
73
|
+
.select(["taxonomy_id"])
|
|
74
|
+
.select((eb) => eb.fn.count<number>("entry_id").as("count"))
|
|
75
|
+
.groupBy("taxonomy_id")
|
|
76
|
+
.execute();
|
|
77
|
+
|
|
78
|
+
const counts = new Map<string, number>();
|
|
79
|
+
for (const row of countsResult) {
|
|
80
|
+
counts.set(row.taxonomy_id, row.count);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const flatTerms: TaxonomyTermRow[] = rows.map((row) => ({
|
|
84
|
+
id: row.id,
|
|
85
|
+
name: row.name,
|
|
86
|
+
slug: row.slug,
|
|
87
|
+
label: row.label,
|
|
88
|
+
parent_id: row.parent_id,
|
|
89
|
+
data: row.data,
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
// If hierarchical, build tree. Otherwise return flat
|
|
93
|
+
if (def.hierarchical) {
|
|
94
|
+
return buildTree(flatTerms, counts);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return flatTerms.map((term) => ({
|
|
98
|
+
id: term.id,
|
|
99
|
+
name: term.name,
|
|
100
|
+
slug: term.slug,
|
|
101
|
+
label: term.label,
|
|
102
|
+
children: [],
|
|
103
|
+
count: counts.get(term.id) ?? 0,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get a single term by taxonomy and slug
|
|
109
|
+
*/
|
|
110
|
+
export async function getTerm(taxonomyName: string, slug: string): Promise<TaxonomyTerm | null> {
|
|
111
|
+
const db = await getDb();
|
|
112
|
+
|
|
113
|
+
const row = await db
|
|
114
|
+
.selectFrom("taxonomies")
|
|
115
|
+
.selectAll()
|
|
116
|
+
.where("name", "=", taxonomyName)
|
|
117
|
+
.where("slug", "=", slug)
|
|
118
|
+
.executeTakeFirst();
|
|
119
|
+
|
|
120
|
+
if (!row) return null;
|
|
121
|
+
|
|
122
|
+
// Get entry count
|
|
123
|
+
const countResult = await db
|
|
124
|
+
.selectFrom("content_taxonomies")
|
|
125
|
+
.select((eb) => eb.fn.count<number>("entry_id").as("count"))
|
|
126
|
+
.where("taxonomy_id", "=", row.id)
|
|
127
|
+
.executeTakeFirst();
|
|
128
|
+
|
|
129
|
+
const count = countResult?.count ?? 0;
|
|
130
|
+
|
|
131
|
+
// Get children if hierarchical
|
|
132
|
+
const childRows = await db
|
|
133
|
+
.selectFrom("taxonomies")
|
|
134
|
+
.selectAll()
|
|
135
|
+
.where("parent_id", "=", row.id)
|
|
136
|
+
.orderBy("label", "asc")
|
|
137
|
+
.execute();
|
|
138
|
+
|
|
139
|
+
const children = childRows.map((child) => ({
|
|
140
|
+
id: child.id,
|
|
141
|
+
name: child.name,
|
|
142
|
+
slug: child.slug,
|
|
143
|
+
label: child.label,
|
|
144
|
+
parentId: child.parent_id ?? undefined,
|
|
145
|
+
children: [],
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
id: row.id,
|
|
150
|
+
name: row.name,
|
|
151
|
+
slug: row.slug,
|
|
152
|
+
label: row.label,
|
|
153
|
+
parentId: row.parent_id ?? undefined,
|
|
154
|
+
description: row.data ? JSON.parse(row.data).description : undefined,
|
|
155
|
+
children,
|
|
156
|
+
count,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get terms assigned to an entry
|
|
162
|
+
*/
|
|
163
|
+
export async function getEntryTerms(
|
|
164
|
+
collection: string,
|
|
165
|
+
entryId: string,
|
|
166
|
+
taxonomyName?: string,
|
|
167
|
+
): Promise<TaxonomyTerm[]> {
|
|
168
|
+
const db = await getDb();
|
|
169
|
+
|
|
170
|
+
let query = db
|
|
171
|
+
.selectFrom("content_taxonomies")
|
|
172
|
+
.innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id")
|
|
173
|
+
.selectAll("taxonomies")
|
|
174
|
+
.where("content_taxonomies.collection", "=", collection)
|
|
175
|
+
.where("content_taxonomies.entry_id", "=", entryId);
|
|
176
|
+
|
|
177
|
+
if (taxonomyName) {
|
|
178
|
+
query = query.where("taxonomies.name", "=", taxonomyName);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const rows = await query.execute();
|
|
182
|
+
|
|
183
|
+
return rows.map((row) => ({
|
|
184
|
+
id: row.id,
|
|
185
|
+
name: row.name,
|
|
186
|
+
slug: row.slug,
|
|
187
|
+
label: row.label,
|
|
188
|
+
parentId: row.parent_id ?? undefined,
|
|
189
|
+
children: [],
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get terms for multiple entries in a single query (batched API)
|
|
195
|
+
*
|
|
196
|
+
* This is more efficient than calling getEntryTerms for each entry
|
|
197
|
+
* when you need terms for a list of entries.
|
|
198
|
+
*
|
|
199
|
+
* @param collection - The collection type (e.g., "posts")
|
|
200
|
+
* @param entryIds - Array of entry IDs
|
|
201
|
+
* @param taxonomyName - The taxonomy name (e.g., "categories")
|
|
202
|
+
* @returns Map from entry ID to array of terms
|
|
203
|
+
*/
|
|
204
|
+
export async function getTermsForEntries(
|
|
205
|
+
collection: string,
|
|
206
|
+
entryIds: string[],
|
|
207
|
+
taxonomyName: string,
|
|
208
|
+
): Promise<Map<string, TaxonomyTerm[]>> {
|
|
209
|
+
const result = new Map<string, TaxonomyTerm[]>();
|
|
210
|
+
|
|
211
|
+
// Initialize all entry IDs with empty arrays
|
|
212
|
+
for (const id of entryIds) {
|
|
213
|
+
result.set(id, []);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (entryIds.length === 0) {
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const db = await getDb();
|
|
221
|
+
|
|
222
|
+
const rows = await db
|
|
223
|
+
.selectFrom("content_taxonomies")
|
|
224
|
+
.innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id")
|
|
225
|
+
.select([
|
|
226
|
+
"content_taxonomies.entry_id",
|
|
227
|
+
"taxonomies.id",
|
|
228
|
+
"taxonomies.name",
|
|
229
|
+
"taxonomies.slug",
|
|
230
|
+
"taxonomies.label",
|
|
231
|
+
"taxonomies.parent_id",
|
|
232
|
+
])
|
|
233
|
+
.where("content_taxonomies.collection", "=", collection)
|
|
234
|
+
.where("content_taxonomies.entry_id", "in", entryIds)
|
|
235
|
+
.where("taxonomies.name", "=", taxonomyName)
|
|
236
|
+
.execute();
|
|
237
|
+
|
|
238
|
+
for (const row of rows) {
|
|
239
|
+
const entryId = row.entry_id;
|
|
240
|
+
const term: TaxonomyTerm = {
|
|
241
|
+
id: row.id,
|
|
242
|
+
name: row.name,
|
|
243
|
+
slug: row.slug,
|
|
244
|
+
label: row.label,
|
|
245
|
+
parentId: row.parent_id ?? undefined,
|
|
246
|
+
children: [],
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const terms = result.get(entryId);
|
|
250
|
+
if (terms) {
|
|
251
|
+
terms.push(term);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get entries by term (wraps getEmDashCollection)
|
|
260
|
+
*/
|
|
261
|
+
export async function getEntriesByTerm(
|
|
262
|
+
collection: string,
|
|
263
|
+
taxonomyName: string,
|
|
264
|
+
termSlug: string,
|
|
265
|
+
): Promise<Array<{ id: string; data: Record<string, unknown> }>> {
|
|
266
|
+
const { getEmDashCollection } = await import("../query.js");
|
|
267
|
+
|
|
268
|
+
// Build options as the expected type — getEmDashCollection accepts
|
|
269
|
+
// a generic options object with `where` for filtering by taxonomy
|
|
270
|
+
const options: Record<string, unknown> = {
|
|
271
|
+
where: { [taxonomyName]: termSlug },
|
|
272
|
+
};
|
|
273
|
+
const { entries } = await getEmDashCollection(collection, options);
|
|
274
|
+
|
|
275
|
+
return entries;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Build tree structure from flat terms
|
|
280
|
+
*/
|
|
281
|
+
function buildTree(flatTerms: TaxonomyTermRow[], counts: Map<string, number>): TaxonomyTerm[] {
|
|
282
|
+
const map = new Map<string, TaxonomyTerm>();
|
|
283
|
+
const roots: TaxonomyTerm[] = [];
|
|
284
|
+
|
|
285
|
+
// First pass: create nodes
|
|
286
|
+
for (const term of flatTerms) {
|
|
287
|
+
map.set(term.id, {
|
|
288
|
+
id: term.id,
|
|
289
|
+
name: term.name,
|
|
290
|
+
slug: term.slug,
|
|
291
|
+
label: term.label,
|
|
292
|
+
parentId: term.parent_id ?? undefined,
|
|
293
|
+
description: term.data ? JSON.parse(term.data).description : undefined,
|
|
294
|
+
children: [],
|
|
295
|
+
count: counts.get(term.id) ?? 0,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Second pass: build tree
|
|
300
|
+
for (const term of map.values()) {
|
|
301
|
+
if (term.parentId && map.has(term.parentId)) {
|
|
302
|
+
map.get(term.parentId)!.children.push(term);
|
|
303
|
+
} else {
|
|
304
|
+
roots.push(term);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return roots;
|
|
309
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taxonomy types for EmDash CMS
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Taxonomy definition - describes a taxonomy like "category" or "tag"
|
|
7
|
+
*/
|
|
8
|
+
export interface TaxonomyDef {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string; // 'category', 'tag', 'genre'
|
|
11
|
+
label: string; // 'Categories', 'Tags'
|
|
12
|
+
labelSingular?: string; // 'Category', 'Tag'
|
|
13
|
+
hierarchical: boolean;
|
|
14
|
+
collections: string[]; // ['posts', 'pages']
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Taxonomy term - a specific term within a taxonomy (e.g., "News" in "category")
|
|
19
|
+
*/
|
|
20
|
+
export interface TaxonomyTerm {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string; // Taxonomy name ('category')
|
|
23
|
+
slug: string; // Term slug ('news')
|
|
24
|
+
label: string; // Display label ('News')
|
|
25
|
+
parentId?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
children: TaxonomyTerm[]; // For tree structure
|
|
28
|
+
count?: number; // Entry count
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Flat version for DB row
|
|
33
|
+
*/
|
|
34
|
+
export interface TaxonomyTermRow {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
slug: string;
|
|
38
|
+
label: string;
|
|
39
|
+
parent_id: string | null;
|
|
40
|
+
data: string | null; // JSON
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Input for creating a term
|
|
45
|
+
*/
|
|
46
|
+
export interface CreateTermInput {
|
|
47
|
+
slug: string;
|
|
48
|
+
label: string;
|
|
49
|
+
parentId?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Input for updating a term
|
|
55
|
+
*/
|
|
56
|
+
export interface UpdateTermInput {
|
|
57
|
+
slug?: string;
|
|
58
|
+
label?: string;
|
|
59
|
+
parentId?: string | null;
|
|
60
|
+
description?: string;
|
|
61
|
+
}
|
package/src/ui.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmDash UI Components
|
|
3
|
+
*
|
|
4
|
+
* Image component for rendering optimized images:
|
|
5
|
+
*
|
|
6
|
+
* ```astro
|
|
7
|
+
* ---
|
|
8
|
+
* import { Image } from "emdash/ui";
|
|
9
|
+
* ---
|
|
10
|
+
* <Image image={post.data.featured_image} />
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Portable Text component for rich content:
|
|
14
|
+
*
|
|
15
|
+
* ```astro
|
|
16
|
+
* ---
|
|
17
|
+
* import { PortableText } from "emdash/ui";
|
|
18
|
+
* ---
|
|
19
|
+
* <PortableText value={post.data.content} />
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Override specific Portable Text components:
|
|
23
|
+
*
|
|
24
|
+
* ```astro
|
|
25
|
+
* <PortableText value={content} components={{ type: { image: MyImage } }} />
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Re-export types and utilities from astro-portabletext
|
|
30
|
+
export {
|
|
31
|
+
type PortableTextProps,
|
|
32
|
+
type TypedObject,
|
|
33
|
+
type SomePortableTextComponents,
|
|
34
|
+
type Block,
|
|
35
|
+
type ArbitraryTypedObject,
|
|
36
|
+
type PortableTextBlock,
|
|
37
|
+
type PortableTextMarkDefinition,
|
|
38
|
+
type PortableTextSpan,
|
|
39
|
+
type PortableTextListItemBlock,
|
|
40
|
+
usePortableText,
|
|
41
|
+
mergeComponents,
|
|
42
|
+
} from "astro-portabletext";
|
|
43
|
+
|
|
44
|
+
// EmDash PortableText wrapper and components
|
|
45
|
+
export {
|
|
46
|
+
// Main Image component for EmDash media
|
|
47
|
+
EmDashImage as Image,
|
|
48
|
+
// Main component (wrapper with EmDash defaults)
|
|
49
|
+
PortableText,
|
|
50
|
+
// Comment components
|
|
51
|
+
Comments,
|
|
52
|
+
CommentForm,
|
|
53
|
+
// Widget components
|
|
54
|
+
WidgetArea,
|
|
55
|
+
// Components object for manual use
|
|
56
|
+
emdashComponents,
|
|
57
|
+
// Portable Text block types (prefixed to avoid collision with Image)
|
|
58
|
+
Image as PTImage,
|
|
59
|
+
Code,
|
|
60
|
+
Embed,
|
|
61
|
+
Gallery,
|
|
62
|
+
Columns,
|
|
63
|
+
Break,
|
|
64
|
+
HtmlBlock,
|
|
65
|
+
// Marks
|
|
66
|
+
Superscript,
|
|
67
|
+
Subscript,
|
|
68
|
+
Underline,
|
|
69
|
+
StrikeThrough,
|
|
70
|
+
Link,
|
|
71
|
+
// Public page contribution components
|
|
72
|
+
EmDashHead,
|
|
73
|
+
EmDashBodyStart,
|
|
74
|
+
EmDashBodyEnd,
|
|
75
|
+
} from "./components/index.js";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 encoding/decoding utilities.
|
|
3
|
+
*
|
|
4
|
+
* Uses native Uint8Array.prototype.toBase64 / Uint8Array.fromBase64 when
|
|
5
|
+
* available (workerd, Node 26+, modern browsers), falls back to btoa/atob.
|
|
6
|
+
*
|
|
7
|
+
* All base64url encoding uses the { alphabet: "base64url" } option natively
|
|
8
|
+
* or manual character replacement as fallback.
|
|
9
|
+
*
|
|
10
|
+
* Delete the fallback paths when the minimum Node version supports these
|
|
11
|
+
* methods natively.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const hasNative =
|
|
15
|
+
typeof Uint8Array.prototype.toBase64 === "function" &&
|
|
16
|
+
typeof Uint8Array.fromBase64 === "function";
|
|
17
|
+
|
|
18
|
+
// Regex patterns for base64url character replacement
|
|
19
|
+
const BASE64_PLUS_PATTERN = /\+/g;
|
|
20
|
+
const BASE64_SLASH_PATTERN = /\//g;
|
|
21
|
+
const BASE64_PADDING_PATTERN = /=+$/;
|
|
22
|
+
const BASE64URL_DASH_PATTERN = /-/g;
|
|
23
|
+
const BASE64URL_UNDERSCORE_PATTERN = /_/g;
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Standard base64 (for opaque tokens, cursors, Basic Auth, etc.)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/** Encode a UTF-8 string as standard base64. */
|
|
30
|
+
export function encodeBase64(str: string): string {
|
|
31
|
+
const bytes = new TextEncoder().encode(str);
|
|
32
|
+
if (hasNative) return bytes.toBase64();
|
|
33
|
+
let binary = "";
|
|
34
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
35
|
+
return btoa(binary);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Decode a standard base64 string to a UTF-8 string. */
|
|
39
|
+
export function decodeBase64(base64: string): string {
|
|
40
|
+
if (hasNative) return new TextDecoder().decode(Uint8Array.fromBase64(base64));
|
|
41
|
+
const binary = atob(base64);
|
|
42
|
+
const bytes = new Uint8Array(binary.length);
|
|
43
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
44
|
+
return new TextDecoder().decode(bytes);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Base64url (for tokens, HMAC signatures, PKCE, etc.)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
/** Encode bytes as base64url without padding. */
|
|
52
|
+
export function encodeBase64url(bytes: Uint8Array): string {
|
|
53
|
+
if (hasNative) return bytes.toBase64({ alphabet: "base64url", omitPadding: true });
|
|
54
|
+
let binary = "";
|
|
55
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
56
|
+
return btoa(binary)
|
|
57
|
+
.replace(BASE64_PLUS_PATTERN, "-")
|
|
58
|
+
.replace(BASE64_SLASH_PATTERN, "_")
|
|
59
|
+
.replace(BASE64_PADDING_PATTERN, "");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Decode a base64url string (with or without padding) to bytes. */
|
|
63
|
+
export function decodeBase64url(encoded: string): Uint8Array {
|
|
64
|
+
if (hasNative) return Uint8Array.fromBase64(encoded, { alphabet: "base64url" });
|
|
65
|
+
const base64 = encoded
|
|
66
|
+
.replace(BASE64URL_DASH_PATTERN, "+")
|
|
67
|
+
.replace(BASE64URL_UNDERSCORE_PATTERN, "/");
|
|
68
|
+
const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
|
|
69
|
+
const binary = atob(padded);
|
|
70
|
+
const bytes = new Uint8Array(binary.length);
|
|
71
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
72
|
+
return bytes;
|
|
73
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
|
|
3
|
+
* For cache invalidation / ETags — not for security.
|
|
4
|
+
*/
|
|
5
|
+
export async function hashString(content: string): Promise<string> {
|
|
6
|
+
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content));
|
|
7
|
+
return Array.from(new Uint8Array(buf).slice(0, 8), (b) => b.toString(16).padStart(2, "0")).join(
|
|
8
|
+
"",
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Compute content hash using Web Crypto API
|
|
14
|
+
*
|
|
15
|
+
* Uses SHA-1 which is the fastest option in SubtleCrypto.
|
|
16
|
+
* SHA-1 is cryptographically weak but fine for content deduplication
|
|
17
|
+
* where we only need to detect identical files, not resist attacks.
|
|
18
|
+
*
|
|
19
|
+
* Returns hex string prefixed with "sha1:" for future-proofing
|
|
20
|
+
*/
|
|
21
|
+
export async function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string> {
|
|
22
|
+
// SubtleCrypto.digest() requires BufferSource (ArrayBuffer | ArrayBufferView<ArrayBuffer>).
|
|
23
|
+
// Uint8Array.buffer is ArrayBufferLike which may include SharedArrayBuffer in the type system,
|
|
24
|
+
// so we ensure we have a plain ArrayBuffer.
|
|
25
|
+
let buf: ArrayBuffer;
|
|
26
|
+
if (content instanceof ArrayBuffer) {
|
|
27
|
+
buf = content;
|
|
28
|
+
} else {
|
|
29
|
+
buf = new ArrayBuffer(content.byteLength);
|
|
30
|
+
new Uint8Array(buf).set(content);
|
|
31
|
+
}
|
|
32
|
+
const hashBuffer = await crypto.subtle.digest("SHA-1", buf);
|
|
33
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
34
|
+
const hashHex = Array.from(hashArray, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
35
|
+
return `sha1:${hashHex}`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import sanitizeHtml from "sanitize-html";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sanitize HTML content to prevent XSS attacks.
|
|
5
|
+
*
|
|
6
|
+
* Allows standard formatting tags, images, iframes (from specific providers),
|
|
7
|
+
* and basic attributes.
|
|
8
|
+
*/
|
|
9
|
+
export function sanitizeContent(html: string): string {
|
|
10
|
+
return sanitizeHtml(html, {
|
|
11
|
+
allowedTags: [...sanitizeHtml.defaults.allowedTags, "img", "span", "iframe"],
|
|
12
|
+
allowedAttributes: {
|
|
13
|
+
...sanitizeHtml.defaults.allowedAttributes,
|
|
14
|
+
"*": ["class", "id", "data-*"],
|
|
15
|
+
iframe: ["src", "width", "height", "frameborder", "allow", "allowfullscreen"],
|
|
16
|
+
img: ["src", "srcset", "alt", "title", "width", "height", "loading"],
|
|
17
|
+
},
|
|
18
|
+
allowedIframeHostnames: ["www.youtube.com", "player.vimeo.com"],
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Regex patterns for slug normalization
|
|
2
|
+
const DIACRITICS_PATTERN = /[\u0300-\u036f]/g;
|
|
3
|
+
const WHITESPACE_UNDERSCORE_PATTERN = /[\s_]+/g;
|
|
4
|
+
const NON_ALPHANUMERIC_HYPHEN_PATTERN = /[^a-z0-9-]/g;
|
|
5
|
+
const MULTIPLE_HYPHENS_PATTERN = /-+/g;
|
|
6
|
+
const LEADING_TRAILING_HYPHEN_PATTERN = /^-|-$/g;
|
|
7
|
+
const TRAILING_HYPHEN_PATTERN = /-$/;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Convert a string to a URL-friendly slug.
|
|
11
|
+
*
|
|
12
|
+
* Handles unicode by normalizing to NFD and stripping diacritics,
|
|
13
|
+
* so "café" becomes "cafe", "naïve" becomes "naive", etc.
|
|
14
|
+
*/
|
|
15
|
+
export function slugify(text: string, maxLength: number = 80): string {
|
|
16
|
+
return (
|
|
17
|
+
text
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.normalize("NFD")
|
|
20
|
+
.replace(DIACRITICS_PATTERN, "")
|
|
21
|
+
.replace(WHITESPACE_UNDERSCORE_PATTERN, "-")
|
|
22
|
+
.replace(NON_ALPHANUMERIC_HYPHEN_PATTERN, "")
|
|
23
|
+
.replace(MULTIPLE_HYPHENS_PATTERN, "-")
|
|
24
|
+
.replace(LEADING_TRAILING_HYPHEN_PATTERN, "")
|
|
25
|
+
.slice(0, maxLength)
|
|
26
|
+
// Clean trailing hyphen from truncation
|
|
27
|
+
.replace(TRAILING_HYPHEN_PATTERN, "")
|
|
28
|
+
);
|
|
29
|
+
}
|
package/src/utils/url.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL scheme validation utilities
|
|
3
|
+
*
|
|
4
|
+
* Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
|
|
5
|
+
* by allowlisting known-safe schemes before rendering into href attributes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Matches URLs that are safe to render in href attributes.
|
|
10
|
+
*
|
|
11
|
+
* Allowed:
|
|
12
|
+
* - http:// and https://
|
|
13
|
+
* - mailto: and tel:
|
|
14
|
+
* - Relative paths (starting with /)
|
|
15
|
+
* - Fragment links (starting with #)
|
|
16
|
+
* - Protocol-relative URLs are NOT allowed (starting with //) as they can
|
|
17
|
+
* redirect to attacker-controlled hosts.
|
|
18
|
+
*/
|
|
19
|
+
const SAFE_URL_SCHEME_RE = /^(https?:|mailto:|tel:|\/(?!\/)|#)/i;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
|
|
23
|
+
*
|
|
24
|
+
* Use this at the render layer as the primary defense against XSS via
|
|
25
|
+
* dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* sanitizeHref("https://example.com") // "https://example.com"
|
|
30
|
+
* sanitizeHref("/about") // "/about"
|
|
31
|
+
* sanitizeHref("#section") // "#section"
|
|
32
|
+
* sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
|
|
33
|
+
* sanitizeHref("javascript:alert(1)") // "#"
|
|
34
|
+
* sanitizeHref("data:text/html,<script>") // "#"
|
|
35
|
+
* sanitizeHref("") // "#"
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function sanitizeHref(url: string | undefined | null): string {
|
|
39
|
+
if (!url) return "#";
|
|
40
|
+
return SAFE_URL_SCHEME_RE.test(url) ? url : "#";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns true if the URL uses a safe scheme for rendering in href attributes.
|
|
45
|
+
*/
|
|
46
|
+
export function isSafeHref(url: string): boolean {
|
|
47
|
+
return SAFE_URL_SCHEME_RE.test(url);
|
|
48
|
+
}
|