emdash 0.0.0-a → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -1
- package/dist/adapters-BLMa4JGD.d.mts +106 -0
- package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
- package/dist/apply-Bjfq_b4-.mjs +1293 -0
- package/dist/apply-Bjfq_b4-.mjs.map +1 -0
- package/dist/astro/index.d.mts +51 -0
- package/dist/astro/index.d.mts.map +1 -0
- package/dist/astro/index.mjs +1333 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/middleware/auth.d.mts +31 -0
- package/dist/astro/middleware/auth.d.mts.map +1 -0
- package/dist/astro/middleware/auth.mjs +654 -0
- package/dist/astro/middleware/auth.mjs.map +1 -0
- package/dist/astro/middleware/redirect.d.mts +22 -0
- package/dist/astro/middleware/redirect.d.mts.map +1 -0
- package/dist/astro/middleware/redirect.mjs +63 -0
- package/dist/astro/middleware/redirect.mjs.map +1 -0
- package/dist/astro/middleware/request-context.d.mts +18 -0
- package/dist/astro/middleware/request-context.d.mts.map +1 -0
- package/dist/astro/middleware/request-context.mjs +1310 -0
- package/dist/astro/middleware/request-context.mjs.map +1 -0
- package/dist/astro/middleware/setup.d.mts +20 -0
- package/dist/astro/middleware/setup.d.mts.map +1 -0
- package/dist/astro/middleware/setup.mjs +47 -0
- package/dist/astro/middleware/setup.mjs.map +1 -0
- package/dist/astro/middleware.d.mts +13 -0
- package/dist/astro/middleware.d.mts.map +1 -0
- package/dist/astro/middleware.mjs +1613 -0
- package/dist/astro/middleware.mjs.map +1 -0
- package/dist/astro/types.d.mts +250 -0
- package/dist/astro/types.d.mts.map +1 -0
- package/dist/astro/types.mjs +1 -0
- package/dist/base64-MBPo9ozB.mjs +59 -0
- package/dist/base64-MBPo9ozB.mjs.map +1 -0
- package/dist/byline-CL847F26.mjs +213 -0
- package/dist/byline-CL847F26.mjs.map +1 -0
- package/dist/bylines-C2a-2TGt.mjs +136 -0
- package/dist/bylines-C2a-2TGt.mjs.map +1 -0
- package/dist/chunk-ClPoSABd.mjs +21 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +3909 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/cf-access.d.mts +60 -0
- package/dist/client/cf-access.d.mts.map +1 -0
- package/dist/client/cf-access.mjs +179 -0
- package/dist/client/cf-access.mjs.map +1 -0
- package/dist/client/index.d.mts +398 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +346 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/config-CKE8p9xM.mjs +55 -0
- package/dist/config-CKE8p9xM.mjs.map +1 -0
- package/dist/connection-B4zVnQIa.mjs +40 -0
- package/dist/connection-B4zVnQIa.mjs.map +1 -0
- package/dist/content-D6C2WsZC.mjs +824 -0
- package/dist/content-D6C2WsZC.mjs.map +1 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.mjs +62 -0
- package/dist/db/index.mjs.map +1 -0
- package/dist/db/libsql.d.mts +11 -0
- package/dist/db/libsql.d.mts.map +1 -0
- package/dist/db/libsql.mjs +17 -0
- package/dist/db/libsql.mjs.map +1 -0
- package/dist/db/postgres.d.mts +11 -0
- package/dist/db/postgres.d.mts.map +1 -0
- package/dist/db/postgres.mjs +30 -0
- package/dist/db/postgres.mjs.map +1 -0
- package/dist/db/sqlite.d.mts +11 -0
- package/dist/db/sqlite.d.mts.map +1 -0
- package/dist/db/sqlite.mjs +16 -0
- package/dist/db/sqlite.mjs.map +1 -0
- package/dist/default-Cyi4aAxu.mjs +81 -0
- package/dist/default-Cyi4aAxu.mjs.map +1 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
- package/dist/error-Cxz0tQeO.mjs +27 -0
- package/dist/error-Cxz0tQeO.mjs.map +1 -0
- package/dist/index-C1xF3OGh.d.mts +4527 -0
- package/dist/index-C1xF3OGh.d.mts.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +30 -0
- package/dist/load-yOOlckBj.mjs +28 -0
- package/dist/load-yOOlckBj.mjs.map +1 -0
- package/dist/loader-fz8Q_3EO.mjs +447 -0
- package/dist/loader-fz8Q_3EO.mjs.map +1 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
- package/dist/media/index.d.mts +26 -0
- package/dist/media/index.d.mts.map +1 -0
- package/dist/media/index.mjs +55 -0
- package/dist/media/index.mjs.map +1 -0
- package/dist/media/local-runtime.d.mts +39 -0
- package/dist/media/local-runtime.d.mts.map +1 -0
- package/dist/media/local-runtime.mjs +133 -0
- package/dist/media/local-runtime.mjs.map +1 -0
- package/dist/media-DqHVh136.mjs +200 -0
- package/dist/media-DqHVh136.mjs.map +1 -0
- package/dist/mode-C2EzN1uE.mjs +23 -0
- package/dist/mode-C2EzN1uE.mjs.map +1 -0
- package/dist/page/index.d.mts +140 -0
- package/dist/page/index.d.mts.map +1 -0
- package/dist/page/index.mjs +416 -0
- package/dist/page/index.mjs.map +1 -0
- package/dist/placeholder-CmGAmqeO.d.mts +276 -0
- package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
- package/dist/placeholder-SmpOx-_v.mjs +243 -0
- package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
- package/dist/plugin-utils.d.mts +58 -0
- package/dist/plugin-utils.d.mts.map +1 -0
- package/dist/plugin-utils.mjs +78 -0
- package/dist/plugin-utils.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
- package/dist/query-CS_iSj34.mjs +460 -0
- package/dist/query-CS_iSj34.mjs.map +1 -0
- package/dist/redirect-DIfIni3r.mjs +329 -0
- package/dist/redirect-DIfIni3r.mjs.map +1 -0
- package/dist/registry-D_w5HW4G.mjs +863 -0
- package/dist/registry-D_w5HW4G.mjs.map +1 -0
- package/dist/request-context.d.mts +49 -0
- package/dist/request-context.d.mts.map +1 -0
- package/dist/request-context.mjs +43 -0
- package/dist/request-context.mjs.map +1 -0
- package/dist/runner-B-u2F2b6.mjs +1412 -0
- package/dist/runner-B-u2F2b6.mjs.map +1 -0
- package/dist/runner-EAtf0ZIe.d.mts +27 -0
- package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
- package/dist/runtime.d.mts +26 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +42 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/search-DG603UrT.mjs +9211 -0
- package/dist/search-DG603UrT.mjs.map +1 -0
- package/dist/seed/index.d.mts +3 -0
- package/dist/seed/index.mjs +15 -0
- package/dist/seo/index.d.mts +70 -0
- package/dist/seo/index.d.mts.map +1 -0
- package/dist/seo/index.mjs +70 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/storage/local.d.mts +39 -0
- package/dist/storage/local.d.mts.map +1 -0
- package/dist/storage/local.mjs +166 -0
- package/dist/storage/local.mjs.map +1 -0
- package/dist/storage/s3.d.mts +32 -0
- package/dist/storage/s3.d.mts.map +1 -0
- package/dist/storage/s3.mjs +175 -0
- package/dist/storage/s3.mjs.map +1 -0
- package/dist/tokens-DpgrkrXK.mjs +171 -0
- package/dist/tokens-DpgrkrXK.mjs.map +1 -0
- package/dist/transport-BFGblqwG.d.mts +42 -0
- package/dist/transport-BFGblqwG.d.mts.map +1 -0
- package/dist/transport-yxiQsi8I.mjs +418 -0
- package/dist/transport-yxiQsi8I.mjs.map +1 -0
- package/dist/types-BRuPJGdV.d.mts +102 -0
- package/dist/types-BRuPJGdV.d.mts.map +1 -0
- package/dist/types-C4-fAxN3.d.mts +182 -0
- package/dist/types-C4-fAxN3.d.mts.map +1 -0
- package/dist/types-CMMN0pNg.mjs +31 -0
- package/dist/types-CMMN0pNg.mjs.map +1 -0
- package/dist/types-CUBbjgmP.mjs +16 -0
- package/dist/types-CUBbjgmP.mjs.map +1 -0
- package/dist/types-DRjfYOEv.d.mts +426 -0
- package/dist/types-DRjfYOEv.d.mts.map +1 -0
- package/dist/types-DY5zk5HN.mjs +73 -0
- package/dist/types-DY5zk5HN.mjs.map +1 -0
- package/dist/types-DaNLHo_T.d.mts +184 -0
- package/dist/types-DaNLHo_T.d.mts.map +1 -0
- package/dist/types-DvhsUmSJ.d.mts +1111 -0
- package/dist/types-DvhsUmSJ.d.mts.map +1 -0
- package/dist/validate-CpBtVMsD.d.mts +378 -0
- package/dist/validate-CpBtVMsD.d.mts.map +1 -0
- package/dist/validate-CqRJb_xU.mjs +97 -0
- package/dist/validate-CqRJb_xU.mjs.map +1 -0
- package/dist/validate-O7PWmlnq.mjs +328 -0
- package/dist/validate-O7PWmlnq.mjs.map +1 -0
- package/locals.d.ts +46 -0
- package/package.json +233 -19
- package/src/api/authorize.ts +63 -0
- package/src/api/csrf.ts +48 -0
- package/src/api/error.ts +99 -0
- package/src/api/errors.ts +445 -0
- package/src/api/escape.ts +9 -0
- package/src/api/handlers/api-tokens.ts +240 -0
- package/src/api/handlers/comments.ts +314 -0
- package/src/api/handlers/content.ts +1315 -0
- package/src/api/handlers/dashboard.ts +205 -0
- package/src/api/handlers/device-flow.ts +687 -0
- package/src/api/handlers/index.ts +163 -0
- package/src/api/handlers/manifest.ts +158 -0
- package/src/api/handlers/marketplace.ts +930 -0
- package/src/api/handlers/media.ts +207 -0
- package/src/api/handlers/menus.ts +493 -0
- package/src/api/handlers/oauth-authorization.ts +429 -0
- package/src/api/handlers/oauth-clients.ts +353 -0
- package/src/api/handlers/oauth-user-lookup.ts +39 -0
- package/src/api/handlers/plugins.ts +254 -0
- package/src/api/handlers/redirects.ts +360 -0
- package/src/api/handlers/revision.ts +145 -0
- package/src/api/handlers/schema.ts +534 -0
- package/src/api/handlers/sections.ts +289 -0
- package/src/api/handlers/seo.ts +115 -0
- package/src/api/handlers/settings.ts +49 -0
- package/src/api/handlers/snapshot.ts +350 -0
- package/src/api/handlers/taxonomies.ts +523 -0
- package/src/api/index.ts +6 -0
- package/src/api/openapi/document.ts +2368 -0
- package/src/api/openapi/index.ts +1 -0
- package/src/api/parse.ts +139 -0
- package/src/api/redirect.ts +14 -0
- package/src/api/rev.ts +67 -0
- package/src/api/schemas/auth.ts +112 -0
- package/src/api/schemas/bylines.ts +85 -0
- package/src/api/schemas/comments.ts +117 -0
- package/src/api/schemas/common.ts +89 -0
- package/src/api/schemas/content.ts +191 -0
- package/src/api/schemas/import.ts +52 -0
- package/src/api/schemas/index.ts +17 -0
- package/src/api/schemas/media.ts +116 -0
- package/src/api/schemas/menus.ts +111 -0
- package/src/api/schemas/redirects.ts +155 -0
- package/src/api/schemas/schema.ts +203 -0
- package/src/api/schemas/search.ts +63 -0
- package/src/api/schemas/sections.ts +67 -0
- package/src/api/schemas/settings.ts +63 -0
- package/src/api/schemas/setup.ts +37 -0
- package/src/api/schemas/taxonomies.ts +113 -0
- package/src/api/schemas/users.ts +96 -0
- package/src/api/schemas/widgets.ts +80 -0
- package/src/api/site-url.ts +25 -0
- package/src/api/types.ts +82 -0
- package/src/astro/index.ts +27 -0
- package/src/astro/integration/index.ts +303 -0
- package/src/astro/integration/routes.ts +834 -0
- package/src/astro/integration/runtime.ts +338 -0
- package/src/astro/integration/virtual-modules.ts +469 -0
- package/src/astro/integration/vite-config.ts +328 -0
- package/src/astro/middleware/auth.ts +743 -0
- package/src/astro/middleware/redirect.ts +89 -0
- package/src/astro/middleware/request-context.ts +129 -0
- package/src/astro/middleware/setup.ts +89 -0
- package/src/astro/middleware.ts +398 -0
- package/src/astro/routes/PluginRegistry.tsx +15 -0
- package/src/astro/routes/admin.astro +81 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +84 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +82 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +117 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
- package/src/astro/routes/api/auth/signup/complete.ts +85 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +105 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
- package/src/astro/routes/api/manifest.ts +62 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +190 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +412 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +51 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +55 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +53 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +100 -0
- package/src/astro/routes/api/setup/admin.ts +94 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +126 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +75 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +77 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +68 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +72 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +77 -0
- package/src/astro/routes/sitemap.xml.ts +97 -0
- package/src/astro/storage/adapters.ts +74 -0
- package/src/astro/storage/index.ts +19 -0
- package/src/astro/storage/types.ts +60 -0
- package/src/astro/types.ts +346 -0
- package/src/auth/api-tokens.ts +25 -0
- package/src/auth/challenge-store.ts +80 -0
- package/src/auth/mode.ts +96 -0
- package/src/auth/oauth-state-store.ts +96 -0
- package/src/auth/passkey-config.ts +27 -0
- package/src/auth/rate-limit.ts +158 -0
- package/src/auth/scopes.ts +33 -0
- package/src/auth/types.ts +104 -0
- package/src/aws-sdk.d.ts +100 -0
- package/src/bylines/index.ts +237 -0
- package/src/cleanup.ts +153 -0
- package/src/cli/client-factory.ts +100 -0
- package/src/cli/commands/auth.ts +46 -0
- package/src/cli/commands/bundle-utils.ts +247 -0
- package/src/cli/commands/bundle.ts +609 -0
- package/src/cli/commands/content.ts +442 -0
- package/src/cli/commands/dev.ts +191 -0
- package/src/cli/commands/doctor.ts +211 -0
- package/src/cli/commands/export-seed.ts +630 -0
- package/src/cli/commands/import/wordpress.ts +1056 -0
- package/src/cli/commands/init.ts +192 -0
- package/src/cli/commands/login.ts +547 -0
- package/src/cli/commands/media.ts +165 -0
- package/src/cli/commands/menu.ts +67 -0
- package/src/cli/commands/plugin-init.ts +291 -0
- package/src/cli/commands/plugin-validate.ts +31 -0
- package/src/cli/commands/plugin.ts +33 -0
- package/src/cli/commands/publish.ts +699 -0
- package/src/cli/commands/schema.ts +233 -0
- package/src/cli/commands/search-cmd.ts +54 -0
- package/src/cli/commands/seed.ts +288 -0
- package/src/cli/commands/taxonomy.ts +128 -0
- package/src/cli/commands/types.ts +68 -0
- package/src/cli/credentials.ts +236 -0
- package/src/cli/index.ts +70 -0
- package/src/cli/output.ts +75 -0
- package/src/cli/wxr/parser.ts +969 -0
- package/src/client/cf-access.ts +193 -0
- package/src/client/index.ts +854 -0
- package/src/client/portable-text.ts +413 -0
- package/src/client/transport.ts +200 -0
- package/src/comments/moderator.ts +46 -0
- package/src/comments/notifications.ts +144 -0
- package/src/comments/query.ts +105 -0
- package/src/comments/service.ts +213 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/EmDashBodyEnd.astro +32 -0
- package/src/components/EmDashBodyStart.astro +32 -0
- package/src/components/EmDashHead.astro +53 -0
- package/src/components/EmDashImage.astro +178 -0
- package/src/components/EmDashMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1905 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/content/converters/index.ts +9 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
- package/src/content/converters/types.ts +120 -0
- package/src/content/index.ts +5 -0
- package/src/database/connection.ts +67 -0
- package/src/database/dialect-helpers.ts +138 -0
- package/src/database/index.ts +5 -0
- package/src/database/migrations/001_initial.ts +136 -0
- package/src/database/migrations/002_media_status.ts +26 -0
- package/src/database/migrations/003_schema_registry.ts +79 -0
- package/src/database/migrations/004_plugins.ts +62 -0
- package/src/database/migrations/005_menus.ts +67 -0
- package/src/database/migrations/006_taxonomy_defs.ts +51 -0
- package/src/database/migrations/007_widgets.ts +42 -0
- package/src/database/migrations/008_auth.ts +194 -0
- package/src/database/migrations/009_user_disabled.ts +27 -0
- package/src/database/migrations/011_sections.ts +65 -0
- package/src/database/migrations/012_search.ts +25 -0
- package/src/database/migrations/013_scheduled_publishing.ts +51 -0
- package/src/database/migrations/014_draft_revisions.ts +72 -0
- package/src/database/migrations/015_indexes.ts +82 -0
- package/src/database/migrations/016_api_tokens.ts +89 -0
- package/src/database/migrations/017_authorization_codes.ts +45 -0
- package/src/database/migrations/018_seo.ts +56 -0
- package/src/database/migrations/019_i18n.ts +618 -0
- package/src/database/migrations/020_collection_url_pattern.ts +23 -0
- package/src/database/migrations/021_remove_section_categories.ts +43 -0
- package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
- package/src/database/migrations/023_plugin_metadata.ts +33 -0
- package/src/database/migrations/024_media_placeholders.ts +32 -0
- package/src/database/migrations/025_oauth_clients.ts +28 -0
- package/src/database/migrations/026_cron_tasks.ts +49 -0
- package/src/database/migrations/027_comments.ts +87 -0
- package/src/database/migrations/028_drop_author_url.ts +9 -0
- package/src/database/migrations/029_redirects.ts +67 -0
- package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
- package/src/database/migrations/031_bylines.ts +90 -0
- package/src/database/migrations/032_rate_limits.ts +42 -0
- package/src/database/migrations/runner.ts +170 -0
- package/src/database/repositories/audit.ts +294 -0
- package/src/database/repositories/byline.ts +387 -0
- package/src/database/repositories/comment.ts +458 -0
- package/src/database/repositories/content.ts +1144 -0
- package/src/database/repositories/index.ts +30 -0
- package/src/database/repositories/media.ts +347 -0
- package/src/database/repositories/options.ts +150 -0
- package/src/database/repositories/plugin-storage.ts +373 -0
- package/src/database/repositories/redirect.ts +480 -0
- package/src/database/repositories/revision.ts +200 -0
- package/src/database/repositories/seo.ts +176 -0
- package/src/database/repositories/taxonomy.ts +294 -0
- package/src/database/repositories/types.ts +132 -0
- package/src/database/repositories/user.ts +258 -0
- package/src/database/transaction.ts +54 -0
- package/src/database/types.ts +501 -0
- package/src/database/validate.ts +138 -0
- package/src/db/adapters.ts +125 -0
- package/src/db/index.ts +37 -0
- package/src/db/libsql.ts +23 -0
- package/src/db/postgres.ts +30 -0
- package/src/db/sqlite.ts +27 -0
- package/src/emdash-runtime.ts +2096 -0
- package/src/fields/boolean.ts +34 -0
- package/src/fields/datetime.ts +44 -0
- package/src/fields/file.ts +41 -0
- package/src/fields/image.ts +34 -0
- package/src/fields/index.ts +42 -0
- package/src/fields/integer.ts +50 -0
- package/src/fields/json.ts +37 -0
- package/src/fields/multiselect.ts +48 -0
- package/src/fields/number.ts +52 -0
- package/src/fields/portable-text.ts +33 -0
- package/src/fields/reference.ts +29 -0
- package/src/fields/richtext.ts +31 -0
- package/src/fields/select.ts +46 -0
- package/src/fields/slug.ts +38 -0
- package/src/fields/text.ts +55 -0
- package/src/fields/textarea.ts +52 -0
- package/src/fields/types.ts +64 -0
- package/src/i18n/config.ts +68 -0
- package/src/import/index.ts +90 -0
- package/src/import/menus.ts +436 -0
- package/src/import/registry.ts +111 -0
- package/src/import/sections.ts +103 -0
- package/src/import/settings.ts +281 -0
- package/src/import/sources/wordpress-plugin.ts +641 -0
- package/src/import/sources/wordpress-rest.ts +191 -0
- package/src/import/sources/wxr.ts +330 -0
- package/src/import/ssrf.ts +260 -0
- package/src/import/types.ts +418 -0
- package/src/import/utils.ts +412 -0
- package/src/index.ts +481 -0
- package/src/loader.ts +770 -0
- package/src/mcp/server.ts +1463 -0
- package/src/media/index.ts +32 -0
- package/src/media/local-runtime.ts +213 -0
- package/src/media/local.ts +46 -0
- package/src/media/normalize.ts +190 -0
- package/src/media/placeholder.ts +150 -0
- package/src/media/provider-loader.ts +78 -0
- package/src/media/types.ts +279 -0
- package/src/menus/index.ts +324 -0
- package/src/menus/types.ts +112 -0
- package/src/page/context.ts +93 -0
- package/src/page/fragments.ts +89 -0
- package/src/page/index.ts +58 -0
- package/src/page/jsonld.ts +94 -0
- package/src/page/metadata.ts +185 -0
- package/src/page/seo-contributions.ts +136 -0
- package/src/plugin-utils.ts +80 -0
- package/src/plugins/adapt-sandbox-entry.ts +207 -0
- package/src/plugins/context.ts +833 -0
- package/src/plugins/cron.ts +361 -0
- package/src/plugins/define-plugin.ts +259 -0
- package/src/plugins/email-console.ts +73 -0
- package/src/plugins/email.ts +209 -0
- package/src/plugins/hooks.ts +1273 -0
- package/src/plugins/index.ts +193 -0
- package/src/plugins/manager.ts +595 -0
- package/src/plugins/manifest-schema.ts +230 -0
- package/src/plugins/marketplace.ts +460 -0
- package/src/plugins/request-meta.ts +139 -0
- package/src/plugins/routes.ts +302 -0
- package/src/plugins/sandbox/index.ts +18 -0
- package/src/plugins/sandbox/noop.ts +76 -0
- package/src/plugins/sandbox/types.ts +173 -0
- package/src/plugins/scheduler/node.ts +122 -0
- package/src/plugins/scheduler/piggyback.ts +71 -0
- package/src/plugins/scheduler/types.ts +27 -0
- package/src/plugins/state.ts +208 -0
- package/src/plugins/storage-indexes.ts +326 -0
- package/src/plugins/storage-query.ts +240 -0
- package/src/plugins/types.ts +1284 -0
- package/src/preview/helpers.ts +27 -0
- package/src/preview/index.ts +40 -0
- package/src/preview/tokens.ts +279 -0
- package/src/preview/urls.ts +118 -0
- package/src/query.ts +674 -0
- package/src/redirects/patterns.ts +224 -0
- package/src/request-context.ts +67 -0
- package/src/runtime.ts +21 -0
- package/src/schema/index.ts +29 -0
- package/src/schema/query.ts +44 -0
- package/src/schema/registry.ts +965 -0
- package/src/schema/types.ts +276 -0
- package/src/schema/zod-generator.ts +413 -0
- package/src/search/fts-manager.ts +452 -0
- package/src/search/index.ts +26 -0
- package/src/search/query.ts +396 -0
- package/src/search/text-extraction.ts +162 -0
- package/src/search/types.ts +114 -0
- package/src/sections/index.ts +226 -0
- package/src/sections/types.ts +86 -0
- package/src/seed/apply.ts +1141 -0
- package/src/seed/default.ts +86 -0
- package/src/seed/index.ts +28 -0
- package/src/seed/load.ts +35 -0
- package/src/seed/types.ts +341 -0
- package/src/seed/validate.ts +642 -0
- package/src/seo/index.ts +179 -0
- package/src/settings/index.ts +203 -0
- package/src/settings/types.ts +58 -0
- package/src/storage/index.ts +28 -0
- package/src/storage/local.ts +253 -0
- package/src/storage/s3.ts +271 -0
- package/src/storage/types.ts +204 -0
- package/src/taxonomies/index.ts +309 -0
- package/src/taxonomies/types.ts +61 -0
- package/src/ui.ts +75 -0
- package/src/utils/base64.ts +73 -0
- package/src/utils/hash.ts +36 -0
- package/src/utils/sanitize.ts +20 -0
- package/src/utils/slugify.ts +29 -0
- package/src/utils/url.ts +48 -0
- package/src/virtual-modules.d.ts +111 -0
- package/src/visual-editing/editable.ts +108 -0
- package/src/visual-editing/toolbar.ts +1229 -0
- package/src/widgets/components.ts +105 -0
- package/src/widgets/index.ts +131 -0
- package/src/widgets/types.ts +81 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Layer Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface for S3-compatible storage backends.
|
|
5
|
+
* Works with R2, AWS S3, Minio, and other S3-compatible services.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Storage configuration for S3-compatible backends
|
|
10
|
+
*/
|
|
11
|
+
export interface S3StorageConfig {
|
|
12
|
+
/** S3 endpoint URL (e.g., "https://xxx.r2.cloudflarestorage.com") */
|
|
13
|
+
endpoint: string;
|
|
14
|
+
/** Bucket name */
|
|
15
|
+
bucket: string;
|
|
16
|
+
/** AWS access key ID */
|
|
17
|
+
accessKeyId: string;
|
|
18
|
+
/** AWS secret access key */
|
|
19
|
+
secretAccessKey: string;
|
|
20
|
+
/** Optional region (defaults to "auto" for R2) */
|
|
21
|
+
region?: string;
|
|
22
|
+
/** Optional public URL prefix for generated URLs (e.g., CDN URL) */
|
|
23
|
+
publicUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Local filesystem storage for development
|
|
28
|
+
*/
|
|
29
|
+
export interface LocalStorageConfig {
|
|
30
|
+
/** Directory path for storing files */
|
|
31
|
+
directory: string;
|
|
32
|
+
/** Base URL for serving files */
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Storage adapter descriptor (serializable config)
|
|
38
|
+
*/
|
|
39
|
+
export interface StorageDescriptor {
|
|
40
|
+
/** Module path exporting createStorage function */
|
|
41
|
+
entrypoint: string;
|
|
42
|
+
/** Serializable config passed to createStorage at runtime */
|
|
43
|
+
config: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Factory function signature for storage adapters
|
|
48
|
+
*
|
|
49
|
+
* Each adapter accesses its own bindings directly:
|
|
50
|
+
* - R2: imports from cloudflare:workers
|
|
51
|
+
* - S3: uses credentials from config
|
|
52
|
+
* - Local: uses filesystem path from config
|
|
53
|
+
*/
|
|
54
|
+
export type CreateStorageFn = (config: Record<string, unknown>) => Storage;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Upload result
|
|
58
|
+
*/
|
|
59
|
+
export interface UploadResult {
|
|
60
|
+
/** Storage key (path within bucket) */
|
|
61
|
+
key: string;
|
|
62
|
+
/** Public URL to access the file */
|
|
63
|
+
url: string;
|
|
64
|
+
/** File size in bytes */
|
|
65
|
+
size: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Download result
|
|
70
|
+
*/
|
|
71
|
+
export interface DownloadResult {
|
|
72
|
+
/** File content as readable stream */
|
|
73
|
+
body: ReadableStream<Uint8Array>;
|
|
74
|
+
/** MIME type */
|
|
75
|
+
contentType: string;
|
|
76
|
+
/** File size in bytes */
|
|
77
|
+
size: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Signed URL for direct upload
|
|
82
|
+
*/
|
|
83
|
+
export interface SignedUploadUrl {
|
|
84
|
+
/** Signed URL for PUT request */
|
|
85
|
+
url: string;
|
|
86
|
+
/** HTTP method (always PUT) */
|
|
87
|
+
method: "PUT";
|
|
88
|
+
/** Headers to include in the upload request */
|
|
89
|
+
headers: Record<string, string>;
|
|
90
|
+
/** URL expiration time (ISO string) */
|
|
91
|
+
expiresAt: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Options for generating signed upload URL
|
|
96
|
+
*/
|
|
97
|
+
export interface SignedUploadOptions {
|
|
98
|
+
/** Storage key (path within bucket) */
|
|
99
|
+
key: string;
|
|
100
|
+
/** MIME type of the file */
|
|
101
|
+
contentType: string;
|
|
102
|
+
/** File size in bytes (for content-length validation) */
|
|
103
|
+
size?: number;
|
|
104
|
+
/** URL expiration in seconds (default: 3600) */
|
|
105
|
+
expiresIn?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* File listing result
|
|
110
|
+
*/
|
|
111
|
+
export interface ListResult {
|
|
112
|
+
/** List of files */
|
|
113
|
+
files: FileInfo[];
|
|
114
|
+
/** Cursor for next page (if more results) */
|
|
115
|
+
nextCursor?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* File info from listing
|
|
120
|
+
*/
|
|
121
|
+
export interface FileInfo {
|
|
122
|
+
/** Storage key */
|
|
123
|
+
key: string;
|
|
124
|
+
/** File size in bytes */
|
|
125
|
+
size: number;
|
|
126
|
+
/** Last modified date */
|
|
127
|
+
lastModified: Date;
|
|
128
|
+
/** ETag (content hash) */
|
|
129
|
+
etag?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Options for listing files
|
|
134
|
+
*/
|
|
135
|
+
export interface ListOptions {
|
|
136
|
+
/** Filter by key prefix */
|
|
137
|
+
prefix?: string;
|
|
138
|
+
/** Maximum results per page */
|
|
139
|
+
limit?: number;
|
|
140
|
+
/** Cursor from previous list call */
|
|
141
|
+
cursor?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Storage interface
|
|
146
|
+
*
|
|
147
|
+
* All storage backends must implement this interface.
|
|
148
|
+
*/
|
|
149
|
+
export interface Storage {
|
|
150
|
+
/**
|
|
151
|
+
* Upload a file to storage
|
|
152
|
+
*/
|
|
153
|
+
upload(options: {
|
|
154
|
+
key: string;
|
|
155
|
+
body: Buffer | Uint8Array | ReadableStream<Uint8Array>;
|
|
156
|
+
contentType: string;
|
|
157
|
+
}): Promise<UploadResult>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Download a file from storage
|
|
161
|
+
*/
|
|
162
|
+
download(key: string): Promise<DownloadResult>;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Delete a file from storage
|
|
166
|
+
* Idempotent - does not throw if file doesn't exist
|
|
167
|
+
*/
|
|
168
|
+
delete(key: string): Promise<void>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Check if a file exists
|
|
172
|
+
*/
|
|
173
|
+
exists(key: string): Promise<boolean>;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* List files in storage
|
|
177
|
+
*/
|
|
178
|
+
list(options?: ListOptions): Promise<ListResult>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Generate a signed URL for direct upload
|
|
182
|
+
* Client uploads directly to storage, bypassing the server
|
|
183
|
+
*/
|
|
184
|
+
getSignedUploadUrl(options: SignedUploadOptions): Promise<SignedUploadUrl>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get public URL for a file
|
|
188
|
+
*/
|
|
189
|
+
getPublicUrl(key: string): string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Storage error with additional context
|
|
194
|
+
*/
|
|
195
|
+
export class EmDashStorageError extends Error {
|
|
196
|
+
constructor(
|
|
197
|
+
message: string,
|
|
198
|
+
public code: string,
|
|
199
|
+
public override cause?: unknown,
|
|
200
|
+
) {
|
|
201
|
+
super(message);
|
|
202
|
+
this.name = "EmDashStorageError";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -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
|
+
}
|