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,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Provider Exports
|
|
3
|
+
*
|
|
4
|
+
* Public API for media providers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
MediaProviderDescriptor,
|
|
10
|
+
MediaProviderCapabilities,
|
|
11
|
+
MediaListOptions,
|
|
12
|
+
MediaListResult,
|
|
13
|
+
MediaProviderItem,
|
|
14
|
+
MediaUploadInput,
|
|
15
|
+
EmbedOptions,
|
|
16
|
+
EmbedResult,
|
|
17
|
+
ImageEmbed,
|
|
18
|
+
VideoEmbed,
|
|
19
|
+
AudioEmbed,
|
|
20
|
+
ComponentEmbed,
|
|
21
|
+
MediaProvider,
|
|
22
|
+
CreateMediaProviderFn,
|
|
23
|
+
MediaValue,
|
|
24
|
+
ThumbnailOptions,
|
|
25
|
+
} from "./types.js";
|
|
26
|
+
|
|
27
|
+
export { mediaItemToValue } from "./types.js";
|
|
28
|
+
export { normalizeMediaValue } from "./normalize.js";
|
|
29
|
+
export { generatePlaceholder, type PlaceholderData } from "./placeholder.js";
|
|
30
|
+
|
|
31
|
+
// Built-in providers
|
|
32
|
+
export { localMedia, type LocalMediaConfig } from "./local.js";
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Media Provider Runtime
|
|
3
|
+
*
|
|
4
|
+
* This is the runtime implementation loaded by the entrypoint.
|
|
5
|
+
* It wraps the existing MediaRepository and storage adapter.
|
|
6
|
+
*
|
|
7
|
+
* Note: This provider is special because it needs access to the database
|
|
8
|
+
* and storage adapter. The createMediaProvider function receives these
|
|
9
|
+
* via the config object, injected by the runtime.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Kysely } from "kysely";
|
|
13
|
+
|
|
14
|
+
import { MediaRepository } from "../database/repositories/media.js";
|
|
15
|
+
import type { Database } from "../database/types.js";
|
|
16
|
+
import type { Storage } from "../index.js";
|
|
17
|
+
import type {
|
|
18
|
+
CreateMediaProviderFn,
|
|
19
|
+
MediaProvider,
|
|
20
|
+
MediaListOptions,
|
|
21
|
+
MediaProviderItem,
|
|
22
|
+
MediaValue,
|
|
23
|
+
EmbedResult,
|
|
24
|
+
EmbedOptions,
|
|
25
|
+
} from "./types.js";
|
|
26
|
+
|
|
27
|
+
export interface LocalMediaRuntimeConfig {
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
// These are injected by the runtime, not from user config
|
|
30
|
+
db?: Kysely<Database>;
|
|
31
|
+
storage?: Storage;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create the local media provider
|
|
36
|
+
*/
|
|
37
|
+
export const createMediaProvider: CreateMediaProviderFn<LocalMediaRuntimeConfig> = (config) => {
|
|
38
|
+
const { db, storage } = config;
|
|
39
|
+
|
|
40
|
+
if (!db) {
|
|
41
|
+
throw new Error("Local media provider requires database connection");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const repo = new MediaRepository(db);
|
|
45
|
+
|
|
46
|
+
const provider: MediaProvider = {
|
|
47
|
+
async list(options: MediaListOptions) {
|
|
48
|
+
const result = await repo.findMany({
|
|
49
|
+
cursor: options.cursor,
|
|
50
|
+
limit: options.limit,
|
|
51
|
+
mimeType: options.mimeType,
|
|
52
|
+
// TODO: Add search support when capabilities.search is true
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
items: result.items.map((item) => ({
|
|
57
|
+
id: item.id,
|
|
58
|
+
filename: item.filename,
|
|
59
|
+
mimeType: item.mimeType,
|
|
60
|
+
size: item.size ?? undefined,
|
|
61
|
+
width: item.width ?? undefined,
|
|
62
|
+
height: item.height ?? undefined,
|
|
63
|
+
alt: item.alt ?? undefined,
|
|
64
|
+
previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
|
|
65
|
+
meta: {
|
|
66
|
+
storageKey: item.storageKey,
|
|
67
|
+
caption: item.caption,
|
|
68
|
+
blurhash: item.blurhash,
|
|
69
|
+
dominantColor: item.dominantColor,
|
|
70
|
+
},
|
|
71
|
+
})),
|
|
72
|
+
nextCursor: result.nextCursor,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async get(id: string) {
|
|
77
|
+
const item = await repo.findById(id);
|
|
78
|
+
if (!item) return null;
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
id: item.id,
|
|
82
|
+
filename: item.filename,
|
|
83
|
+
mimeType: item.mimeType,
|
|
84
|
+
size: item.size ?? undefined,
|
|
85
|
+
width: item.width ?? undefined,
|
|
86
|
+
height: item.height ?? undefined,
|
|
87
|
+
alt: item.alt ?? undefined,
|
|
88
|
+
previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
|
|
89
|
+
meta: {
|
|
90
|
+
storageKey: item.storageKey,
|
|
91
|
+
caption: item.caption,
|
|
92
|
+
blurhash: item.blurhash,
|
|
93
|
+
dominantColor: item.dominantColor,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
async upload(_input) {
|
|
99
|
+
if (!storage) {
|
|
100
|
+
throw new Error("Storage not configured for local media provider");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// This is handled by the existing media upload endpoint
|
|
104
|
+
// The provider interface is used by external providers
|
|
105
|
+
// For local, we delegate to the existing system
|
|
106
|
+
throw new Error("Local upload should use /_emdash/api/media endpoint");
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async delete(id: string) {
|
|
110
|
+
const item = await repo.findById(id);
|
|
111
|
+
if (!item) return;
|
|
112
|
+
|
|
113
|
+
// Delete from storage if available
|
|
114
|
+
if (storage) {
|
|
115
|
+
try {
|
|
116
|
+
await storage.delete(item.storageKey);
|
|
117
|
+
} catch {
|
|
118
|
+
// Ignore storage deletion errors
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await repo.delete(id);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
getEmbed(value: MediaValue, _options?: EmbedOptions): EmbedResult {
|
|
126
|
+
const storageKey =
|
|
127
|
+
typeof value.meta?.storageKey === "string" ? value.meta.storageKey : value.id;
|
|
128
|
+
const src = `/_emdash/api/media/file/${storageKey}`;
|
|
129
|
+
const mimeType = value.mimeType || "";
|
|
130
|
+
|
|
131
|
+
// Determine embed type based on MIME type
|
|
132
|
+
if (mimeType.startsWith("image/")) {
|
|
133
|
+
return {
|
|
134
|
+
type: "image",
|
|
135
|
+
src,
|
|
136
|
+
width: value.width,
|
|
137
|
+
height: value.height,
|
|
138
|
+
alt: value.alt,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (mimeType.startsWith("video/")) {
|
|
143
|
+
return {
|
|
144
|
+
type: "video",
|
|
145
|
+
src,
|
|
146
|
+
width: value.width,
|
|
147
|
+
height: value.height,
|
|
148
|
+
controls: true,
|
|
149
|
+
preload: "metadata",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (mimeType.startsWith("audio/")) {
|
|
154
|
+
return {
|
|
155
|
+
type: "audio",
|
|
156
|
+
src,
|
|
157
|
+
controls: true,
|
|
158
|
+
preload: "metadata",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Fallback: treat as image (for unknown types)
|
|
163
|
+
return {
|
|
164
|
+
type: "image",
|
|
165
|
+
src,
|
|
166
|
+
width: value.width,
|
|
167
|
+
height: value.height,
|
|
168
|
+
alt: value.alt,
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
getThumbnailUrl(id: string, _mimeType?: string) {
|
|
173
|
+
// For local media, return the file URL
|
|
174
|
+
return `/_emdash/api/media/file/${id}`;
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return provider;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Helper to convert a MediaRepository item to MediaProviderItem
|
|
183
|
+
*/
|
|
184
|
+
export function repoItemToProviderItem(item: {
|
|
185
|
+
id: string;
|
|
186
|
+
filename: string;
|
|
187
|
+
mimeType: string;
|
|
188
|
+
size: number | null;
|
|
189
|
+
width: number | null;
|
|
190
|
+
height: number | null;
|
|
191
|
+
alt: string | null;
|
|
192
|
+
caption: string | null;
|
|
193
|
+
storageKey: string;
|
|
194
|
+
blurhash: string | null;
|
|
195
|
+
dominantColor: string | null;
|
|
196
|
+
}): MediaProviderItem {
|
|
197
|
+
return {
|
|
198
|
+
id: item.id,
|
|
199
|
+
filename: item.filename,
|
|
200
|
+
mimeType: item.mimeType,
|
|
201
|
+
size: item.size ?? undefined,
|
|
202
|
+
width: item.width ?? undefined,
|
|
203
|
+
height: item.height ?? undefined,
|
|
204
|
+
alt: item.alt ?? undefined,
|
|
205
|
+
previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
|
|
206
|
+
meta: {
|
|
207
|
+
storageKey: item.storageKey,
|
|
208
|
+
caption: item.caption,
|
|
209
|
+
blurhash: item.blurhash,
|
|
210
|
+
dominantColor: item.dominantColor,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Media Provider
|
|
3
|
+
*
|
|
4
|
+
* The built-in media provider that wraps the current storage adapter and media database.
|
|
5
|
+
* This is the default provider and is available unless explicitly disabled.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { MediaProviderDescriptor } from "./types.js";
|
|
9
|
+
|
|
10
|
+
export interface LocalMediaConfig {
|
|
11
|
+
/** Whether the local provider is enabled (default true) */
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Local media provider configuration
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { localMedia } from "emdash/media";
|
|
21
|
+
*
|
|
22
|
+
* emdash({
|
|
23
|
+
* mediaProviders: [
|
|
24
|
+
* localMedia(), // Uses defaults
|
|
25
|
+
* // or: localMedia({ enabled: false }) to disable
|
|
26
|
+
* ],
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function localMedia(config: LocalMediaConfig = {}): MediaProviderDescriptor {
|
|
31
|
+
return {
|
|
32
|
+
id: "local",
|
|
33
|
+
name: "Library",
|
|
34
|
+
icon: "📁",
|
|
35
|
+
entrypoint: "emdash/media/local-runtime",
|
|
36
|
+
capabilities: {
|
|
37
|
+
browse: true,
|
|
38
|
+
search: false, // TODO: Add search support
|
|
39
|
+
upload: true,
|
|
40
|
+
delete: true,
|
|
41
|
+
},
|
|
42
|
+
config: {
|
|
43
|
+
enabled: config.enabled ?? true,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Value Normalization
|
|
3
|
+
*
|
|
4
|
+
* Normalizes media field values into a consistent shape regardless of
|
|
5
|
+
* creation path (seed scripts, media picker, WP import, URL input).
|
|
6
|
+
*
|
|
7
|
+
* Called at content create/update time when a media provider is available,
|
|
8
|
+
* filling in missing dimensions, storageKey, mimeType, and filename from
|
|
9
|
+
* the provider's `get()` method.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { MediaProvider, MediaProviderItem, MediaValue } from "./types.js";
|
|
13
|
+
|
|
14
|
+
const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
|
|
15
|
+
const URL_PATTERN = /^https?:\/\//;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Normalize a media field value into a consistent MediaValue shape.
|
|
19
|
+
*
|
|
20
|
+
* - `null`/`undefined` → `null`
|
|
21
|
+
* - Bare URL string → `{ provider: "external", id: "", src: url }`
|
|
22
|
+
* - Bare internal media URL → resolved via local provider's `get()`
|
|
23
|
+
* - Object with `provider` + `id` → enriched with missing fields from provider
|
|
24
|
+
*/
|
|
25
|
+
export async function normalizeMediaValue(
|
|
26
|
+
value: unknown,
|
|
27
|
+
getProvider: (id: string) => MediaProvider | undefined,
|
|
28
|
+
): Promise<MediaValue | null> {
|
|
29
|
+
if (value == null) return null;
|
|
30
|
+
|
|
31
|
+
// Bare string URL
|
|
32
|
+
if (typeof value === "string") {
|
|
33
|
+
return normalizeStringUrl(value, getProvider);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Not an object — can't normalize
|
|
37
|
+
if (!isRecord(value)) return null;
|
|
38
|
+
|
|
39
|
+
// Must have at least an id to be a valid media value
|
|
40
|
+
if (!("id" in value) && !("src" in value)) return null;
|
|
41
|
+
|
|
42
|
+
const provider = (typeof value.provider === "string" ? value.provider : undefined) || "local";
|
|
43
|
+
const id = typeof value.id === "string" ? value.id : "";
|
|
44
|
+
|
|
45
|
+
// External URLs — return as-is, no server-side dimension detection
|
|
46
|
+
if (provider === "external") {
|
|
47
|
+
return recordToMediaValue(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Build the base value from the input
|
|
51
|
+
const result: MediaValue = { ...recordToMediaValue(value), provider };
|
|
52
|
+
|
|
53
|
+
// For local media, strip `src` — it's derived at display time from storageKey
|
|
54
|
+
if (provider === "local") {
|
|
55
|
+
delete result.src;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Determine if we need to call the provider
|
|
59
|
+
const needsDimensions = result.width == null || result.height == null;
|
|
60
|
+
const needsStorageKey = provider === "local" && !result.meta?.storageKey;
|
|
61
|
+
const needsFileInfo = !result.mimeType || !result.filename;
|
|
62
|
+
const needsLookup = needsDimensions || needsStorageKey || needsFileInfo;
|
|
63
|
+
|
|
64
|
+
if (!needsLookup || !id) return result;
|
|
65
|
+
|
|
66
|
+
// Try to enrich from provider
|
|
67
|
+
const mediaProvider = getProvider(provider);
|
|
68
|
+
if (!mediaProvider?.get) return result;
|
|
69
|
+
|
|
70
|
+
let providerItem: MediaProviderItem | null;
|
|
71
|
+
try {
|
|
72
|
+
providerItem = await mediaProvider.get(id);
|
|
73
|
+
} catch {
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!providerItem) return result;
|
|
78
|
+
|
|
79
|
+
return mergeProviderData(result, providerItem);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizeStringUrl(
|
|
83
|
+
url: string,
|
|
84
|
+
getProvider: (id: string) => MediaProvider | undefined,
|
|
85
|
+
): Promise<MediaValue | null> {
|
|
86
|
+
// Internal media URL — try to resolve via local provider
|
|
87
|
+
if (url.startsWith(INTERNAL_MEDIA_PREFIX)) {
|
|
88
|
+
return resolveInternalUrl(url, getProvider);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// External HTTP(S) URL
|
|
92
|
+
if (URL_PATTERN.test(url)) {
|
|
93
|
+
return Promise.resolve({
|
|
94
|
+
provider: "external",
|
|
95
|
+
id: "",
|
|
96
|
+
src: url,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Unrecognized string — treat as external
|
|
101
|
+
return Promise.resolve({
|
|
102
|
+
provider: "external",
|
|
103
|
+
id: "",
|
|
104
|
+
src: url,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function resolveInternalUrl(
|
|
109
|
+
url: string,
|
|
110
|
+
getProvider: (id: string) => MediaProvider | undefined,
|
|
111
|
+
): Promise<MediaValue> {
|
|
112
|
+
const storageKey = url.slice(INTERNAL_MEDIA_PREFIX.length);
|
|
113
|
+
const localProvider = getProvider("local");
|
|
114
|
+
|
|
115
|
+
if (!localProvider?.get) {
|
|
116
|
+
return { provider: "external", id: "", src: url };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let item: MediaProviderItem | null;
|
|
120
|
+
try {
|
|
121
|
+
item = await localProvider.get(storageKey);
|
|
122
|
+
} catch {
|
|
123
|
+
return { provider: "external", id: "", src: url };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!item) {
|
|
127
|
+
return { provider: "external", id: "", src: url };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
provider: "local",
|
|
132
|
+
id: item.id,
|
|
133
|
+
filename: item.filename,
|
|
134
|
+
mimeType: item.mimeType,
|
|
135
|
+
width: item.width,
|
|
136
|
+
height: item.height,
|
|
137
|
+
alt: item.alt,
|
|
138
|
+
meta: item.meta,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Merge provider data into an existing MediaValue, preserving caller-supplied fields.
|
|
144
|
+
* Caller `alt` takes priority over provider `alt` (per-usage, not per-image).
|
|
145
|
+
*/
|
|
146
|
+
function mergeProviderData(existing: MediaValue, item: MediaProviderItem): MediaValue {
|
|
147
|
+
const result = { ...existing };
|
|
148
|
+
|
|
149
|
+
// Fill missing dimensions
|
|
150
|
+
if (result.width == null && item.width != null) result.width = item.width;
|
|
151
|
+
if (result.height == null && item.height != null) result.height = item.height;
|
|
152
|
+
|
|
153
|
+
// Fill missing file info
|
|
154
|
+
if (!result.filename && item.filename) result.filename = item.filename;
|
|
155
|
+
if (!result.mimeType && item.mimeType) result.mimeType = item.mimeType;
|
|
156
|
+
|
|
157
|
+
// Fill missing alt (provider alt is fallback, not override)
|
|
158
|
+
if (!result.alt && item.alt) result.alt = item.alt;
|
|
159
|
+
|
|
160
|
+
// Fill missing meta (merge, don't replace)
|
|
161
|
+
if (item.meta) {
|
|
162
|
+
result.meta = { ...item.meta, ...result.meta };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
169
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Extract known MediaValue fields from a runtime-checked record.
|
|
174
|
+
* Avoids unsafe `as MediaValue` cast by reading each property explicitly.
|
|
175
|
+
*/
|
|
176
|
+
function recordToMediaValue(obj: Record<string, unknown>): MediaValue {
|
|
177
|
+
const result: MediaValue = {
|
|
178
|
+
id: typeof obj.id === "string" ? obj.id : "",
|
|
179
|
+
};
|
|
180
|
+
if (typeof obj.provider === "string") result.provider = obj.provider;
|
|
181
|
+
if (typeof obj.src === "string") result.src = obj.src;
|
|
182
|
+
if (typeof obj.previewUrl === "string") result.previewUrl = obj.previewUrl;
|
|
183
|
+
if (typeof obj.filename === "string") result.filename = obj.filename;
|
|
184
|
+
if (typeof obj.mimeType === "string") result.mimeType = obj.mimeType;
|
|
185
|
+
if (typeof obj.width === "number") result.width = obj.width;
|
|
186
|
+
if (typeof obj.height === "number") result.height = obj.height;
|
|
187
|
+
if (typeof obj.alt === "string") result.alt = obj.alt;
|
|
188
|
+
if (isRecord(obj.meta)) result.meta = obj.meta;
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Placeholder Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates blurhash and dominant color from image buffers for LQIP support.
|
|
5
|
+
* Decodes images via jpeg-js (pure JS) and upng-js (pure JS, uses pako for
|
|
6
|
+
* deflate). No Node-specific dependencies — works in Workers and Node SSR.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { encode } from "blurhash";
|
|
10
|
+
|
|
11
|
+
export interface PlaceholderData {
|
|
12
|
+
blurhash: string;
|
|
13
|
+
dominantColor: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SUPPORTED_TYPES: Record<string, "jpeg" | "png"> = {
|
|
17
|
+
"image/jpeg": "jpeg",
|
|
18
|
+
"image/jpg": "jpeg",
|
|
19
|
+
"image/png": "png",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Max width for blurhash input. Encode is O(w*h*components), so downsample first. */
|
|
23
|
+
const MAX_ENCODE_WIDTH = 32;
|
|
24
|
+
|
|
25
|
+
interface DecodedImage {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
data: Uint8Array;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Decode a JPEG buffer into raw RGBA pixel data.
|
|
33
|
+
*/
|
|
34
|
+
async function decodeJpeg(buffer: Uint8Array): Promise<DecodedImage> {
|
|
35
|
+
const { decode } = await import("jpeg-js");
|
|
36
|
+
const result = decode(buffer, { useTArray: true });
|
|
37
|
+
return { width: result.width, height: result.height, data: result.data };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Decode a PNG buffer into raw RGBA pixel data.
|
|
42
|
+
* Uses upng-js (pure JS with pako deflate) — no Node zlib dependency.
|
|
43
|
+
*/
|
|
44
|
+
async function decodePng(buffer: Uint8Array): Promise<DecodedImage> {
|
|
45
|
+
// @ts-expect-error -- upng-js has no type declarations
|
|
46
|
+
const UPNG = (await import("upng-js")).default;
|
|
47
|
+
const img = UPNG.decode(buffer.buffer);
|
|
48
|
+
// toRGBA8 returns an array of frames; take the first frame
|
|
49
|
+
const frames: ArrayBuffer[] = UPNG.toRGBA8(img);
|
|
50
|
+
const rgba = new Uint8Array(frames[0]);
|
|
51
|
+
return { width: img.width, height: img.height, data: rgba };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Extract the dominant color from RGBA pixel data.
|
|
56
|
+
* Simple average of all non-transparent pixels.
|
|
57
|
+
*/
|
|
58
|
+
function extractDominantColor(data: Uint8Array, width: number, height: number): string {
|
|
59
|
+
let r = 0;
|
|
60
|
+
let g = 0;
|
|
61
|
+
let b = 0;
|
|
62
|
+
let count = 0;
|
|
63
|
+
|
|
64
|
+
const len = width * height * 4;
|
|
65
|
+
for (let i = 0; i < len; i += 4) {
|
|
66
|
+
const a = data[i + 3];
|
|
67
|
+
if (a < 128) continue; // skip mostly-transparent pixels
|
|
68
|
+
r += data[i];
|
|
69
|
+
g += data[i + 1];
|
|
70
|
+
b += data[i + 2];
|
|
71
|
+
count++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (count === 0) return "rgb(0,0,0)";
|
|
75
|
+
|
|
76
|
+
const avgR = Math.round(r / count);
|
|
77
|
+
const avgG = Math.round(g / count);
|
|
78
|
+
const avgB = Math.round(b / count);
|
|
79
|
+
return `rgb(${avgR},${avgG},${avgB})`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate blurhash and dominant color from an image buffer.
|
|
84
|
+
* Returns null for non-image MIME types or on failure.
|
|
85
|
+
*/
|
|
86
|
+
export async function generatePlaceholder(
|
|
87
|
+
buffer: Uint8Array,
|
|
88
|
+
mimeType: string,
|
|
89
|
+
): Promise<PlaceholderData | null> {
|
|
90
|
+
const format = SUPPORTED_TYPES[mimeType];
|
|
91
|
+
if (!format) return null;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const imageData = format === "jpeg" ? await decodeJpeg(buffer) : await decodePng(buffer);
|
|
95
|
+
const { width, height, data } = imageData;
|
|
96
|
+
|
|
97
|
+
if (width === 0 || height === 0) return null;
|
|
98
|
+
|
|
99
|
+
// Downsample for blurhash encoding if needed
|
|
100
|
+
let encodePixels: Uint8ClampedArray;
|
|
101
|
+
let encodeWidth: number;
|
|
102
|
+
let encodeHeight: number;
|
|
103
|
+
|
|
104
|
+
if (width > MAX_ENCODE_WIDTH) {
|
|
105
|
+
const scale = MAX_ENCODE_WIDTH / width;
|
|
106
|
+
encodeWidth = MAX_ENCODE_WIDTH;
|
|
107
|
+
encodeHeight = Math.max(1, Math.round(height * scale));
|
|
108
|
+
encodePixels = downsample(data, width, height, encodeWidth, encodeHeight);
|
|
109
|
+
} else {
|
|
110
|
+
encodeWidth = width;
|
|
111
|
+
encodeHeight = height;
|
|
112
|
+
encodePixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const blurhash = encode(encodePixels, encodeWidth, encodeHeight, 4, 3);
|
|
116
|
+
const dominantColor = extractDominantColor(data, width, height);
|
|
117
|
+
|
|
118
|
+
return { blurhash, dominantColor };
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Nearest-neighbor downsample of RGBA pixel data.
|
|
126
|
+
*/
|
|
127
|
+
function downsample(
|
|
128
|
+
src: Uint8Array,
|
|
129
|
+
srcW: number,
|
|
130
|
+
srcH: number,
|
|
131
|
+
dstW: number,
|
|
132
|
+
dstH: number,
|
|
133
|
+
): Uint8ClampedArray {
|
|
134
|
+
const dst = new Uint8ClampedArray(dstW * dstH * 4);
|
|
135
|
+
|
|
136
|
+
for (let y = 0; y < dstH; y++) {
|
|
137
|
+
const srcY = Math.floor((y * srcH) / dstH);
|
|
138
|
+
for (let x = 0; x < dstW; x++) {
|
|
139
|
+
const srcX = Math.floor((x * srcW) / dstW);
|
|
140
|
+
const srcIdx = (srcY * srcW + srcX) * 4;
|
|
141
|
+
const dstIdx = (y * dstW + x) * 4;
|
|
142
|
+
dst[dstIdx] = src[srcIdx]!;
|
|
143
|
+
dst[dstIdx + 1] = src[srcIdx + 1]!;
|
|
144
|
+
dst[dstIdx + 2] = src[srcIdx + 2]!;
|
|
145
|
+
dst[dstIdx + 3] = src[srcIdx + 3]!;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return dst;
|
|
150
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Provider Loader
|
|
3
|
+
*
|
|
4
|
+
* Lazy-loads media providers from virtual module for frontend rendering.
|
|
5
|
+
* Similar pattern to getDb() - providers are loaded on first use and cached.
|
|
6
|
+
*
|
|
7
|
+
* This allows EmDashMedia component to render media without requiring
|
|
8
|
+
* the full EmDash runtime to be initialized.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { MediaProvider, MediaProviderCapabilities } from "./types.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Media provider entry from virtual module
|
|
15
|
+
*/
|
|
16
|
+
interface MediaProviderEntry {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
icon?: string;
|
|
20
|
+
capabilities: MediaProviderCapabilities;
|
|
21
|
+
createProvider: (ctx: Record<string, unknown>) => MediaProvider;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Cached provider entries from virtual module
|
|
25
|
+
let virtualMediaProviders: MediaProviderEntry[] | undefined;
|
|
26
|
+
|
|
27
|
+
// Cached provider instances (shared across calls)
|
|
28
|
+
const mediaProviderInstances = new Map<string, MediaProvider>();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Load media providers from virtual module
|
|
32
|
+
*/
|
|
33
|
+
async function loadMediaProviders(): Promise<void> {
|
|
34
|
+
if (virtualMediaProviders === undefined) {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
36
|
+
// @ts-ignore - virtual module
|
|
37
|
+
const providersModule = await import("virtual:emdash/media-providers");
|
|
38
|
+
virtualMediaProviders = providersModule.mediaProviders || [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get a media provider by ID.
|
|
44
|
+
*
|
|
45
|
+
* Used by EmDashMedia component for frontend rendering.
|
|
46
|
+
* Providers are lazy-loaded from virtual module and cached.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const provider = await getMediaProvider("cloudflare-images");
|
|
51
|
+
* if (provider) {
|
|
52
|
+
* const embed = provider.getEmbed(mediaValue, { width: 800 });
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export async function getMediaProvider(providerId: string): Promise<MediaProvider | undefined> {
|
|
57
|
+
// Check cache first
|
|
58
|
+
const cached = mediaProviderInstances.get(providerId);
|
|
59
|
+
if (cached) {
|
|
60
|
+
return cached;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Load media providers from virtual module
|
|
64
|
+
await loadMediaProviders();
|
|
65
|
+
|
|
66
|
+
// Find the provider entry
|
|
67
|
+
const entry = virtualMediaProviders?.find((p) => p.id === providerId);
|
|
68
|
+
if (!entry) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Create the provider instance
|
|
73
|
+
// For providers that don't need db/storage (like Cloudflare Images),
|
|
74
|
+
// they'll get empty context and use env vars directly
|
|
75
|
+
const provider = entry.createProvider({});
|
|
76
|
+
mediaProviderInstances.set(providerId, provider);
|
|
77
|
+
return provider;
|
|
78
|
+
}
|