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
package/src/query.ts
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query functions for EmDash content
|
|
3
|
+
*
|
|
4
|
+
* These wrap Astro's getLiveCollection/getLiveEntry with type filtering.
|
|
5
|
+
* Use these instead of calling Astro's functions directly.
|
|
6
|
+
*
|
|
7
|
+
* Error handling follows Astro's pattern - returns { entries/entry, error }
|
|
8
|
+
* so callers can gracefully handle errors (including 404s).
|
|
9
|
+
*
|
|
10
|
+
* Preview mode is handled implicitly via ALS request context —
|
|
11
|
+
* no parameters needed. The middleware verifies the preview token
|
|
12
|
+
* and sets the context; query functions read it automatically.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { getFallbackChain, getI18nConfig, isI18nEnabled } from "./i18n/config.js";
|
|
16
|
+
import { getRequestContext } from "./request-context.js";
|
|
17
|
+
import {
|
|
18
|
+
createEditable,
|
|
19
|
+
createNoop,
|
|
20
|
+
type EditProxy,
|
|
21
|
+
type EditableOptions,
|
|
22
|
+
} from "./visual-editing/editable.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Collection type registry for type-safe queries.
|
|
26
|
+
*
|
|
27
|
+
* This interface is extended by the generated emdash-env.d.ts file
|
|
28
|
+
* to provide type inference for collection names and their data shapes.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // In emdash-env.d.ts (generated):
|
|
33
|
+
* declare module "emdash" {
|
|
34
|
+
* interface EmDashCollections {
|
|
35
|
+
* posts: { title: string; content: PortableTextBlock[]; };
|
|
36
|
+
* pages: { title: string; body: PortableTextBlock[]; };
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Then in your code:
|
|
41
|
+
* const { entries } = await getEmDashCollection("posts");
|
|
42
|
+
* // entries[0].data.title is typed as string
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
46
|
+
export interface EmDashCollections {}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Helper type to infer the data type for a collection.
|
|
50
|
+
* Returns the registered type if known, otherwise falls back to Record<string, unknown>.
|
|
51
|
+
*/
|
|
52
|
+
export type InferCollectionData<T extends string> = T extends keyof EmDashCollections
|
|
53
|
+
? EmDashCollections[T]
|
|
54
|
+
: Record<string, unknown>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Sort direction
|
|
58
|
+
*/
|
|
59
|
+
export type SortDirection = "asc" | "desc";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Order by specification - field name to direction
|
|
63
|
+
* @example { created_at: "desc" } - Sort by created_at descending
|
|
64
|
+
* @example { title: "asc" } - Sort by title ascending
|
|
65
|
+
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
66
|
+
*/
|
|
67
|
+
export type OrderBySpec = Record<string, SortDirection>;
|
|
68
|
+
|
|
69
|
+
export interface CollectionFilter {
|
|
70
|
+
status?: "draft" | "published" | "archived";
|
|
71
|
+
limit?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Opaque cursor for keyset pagination.
|
|
74
|
+
* Pass the `nextCursor` value from a previous result to fetch the next page.
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
|
|
78
|
+
* const { entries, nextCursor } = await getEmDashCollection("posts", {
|
|
79
|
+
* limit: 10,
|
|
80
|
+
* cursor,
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
cursor?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Filter by field values or taxonomy terms
|
|
87
|
+
* @example { category: 'news' } - Filter by taxonomy term
|
|
88
|
+
* @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
|
|
89
|
+
*/
|
|
90
|
+
where?: Record<string, string | string[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Order results by field(s)
|
|
93
|
+
* @default { created_at: "desc" }
|
|
94
|
+
* @example { created_at: "desc" } - Sort by created_at descending (default)
|
|
95
|
+
* @example { title: "asc" } - Sort by title ascending
|
|
96
|
+
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
97
|
+
*/
|
|
98
|
+
orderBy?: OrderBySpec;
|
|
99
|
+
/**
|
|
100
|
+
* Filter by locale. When set, only returns entries in this locale.
|
|
101
|
+
* Only relevant when i18n is configured.
|
|
102
|
+
* @example "en" — English entries only
|
|
103
|
+
* @example "fr" — French entries only
|
|
104
|
+
*/
|
|
105
|
+
locale?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ContentEntry<T = Record<string, unknown>> {
|
|
109
|
+
id: string;
|
|
110
|
+
data: T;
|
|
111
|
+
/** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
|
|
112
|
+
edit: EditProxy;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Cache hint returned by the content loader for route caching */
|
|
116
|
+
export interface CacheHint {
|
|
117
|
+
tags?: string[];
|
|
118
|
+
lastModified?: Date;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Result from getEmDashCollection
|
|
123
|
+
*/
|
|
124
|
+
export interface CollectionResult<T> {
|
|
125
|
+
/** The entries (empty array if error or none found) */
|
|
126
|
+
entries: ContentEntry<T>[];
|
|
127
|
+
/** Error if the query failed */
|
|
128
|
+
error?: Error;
|
|
129
|
+
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
130
|
+
cacheHint: CacheHint;
|
|
131
|
+
/**
|
|
132
|
+
* Opaque cursor for the next page.
|
|
133
|
+
* Undefined when there are no more results.
|
|
134
|
+
* Pass this as `cursor` in the next query to get the next page.
|
|
135
|
+
*/
|
|
136
|
+
nextCursor?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Result from getEmDashEntry
|
|
141
|
+
*/
|
|
142
|
+
export interface EntryResult<T> {
|
|
143
|
+
/** The entry, or null if not found */
|
|
144
|
+
entry: ContentEntry<T> | null;
|
|
145
|
+
/** Error if the query failed (not set for "not found", only for actual errors) */
|
|
146
|
+
error?: Error;
|
|
147
|
+
/** Whether we're in preview mode (valid token was provided) */
|
|
148
|
+
isPreview: boolean;
|
|
149
|
+
/** Set when a fallback locale was used instead of the requested locale */
|
|
150
|
+
fallbackLocale?: string;
|
|
151
|
+
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
152
|
+
cacheHint: CacheHint;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const COLLECTION_NAME = "_emdash";
|
|
156
|
+
|
|
157
|
+
/** Symbol key for edit metadata on PT arrays — avoids collision with user data */
|
|
158
|
+
const EMDASH_EDIT = Symbol.for("__emdash");
|
|
159
|
+
|
|
160
|
+
/** Edit metadata attached to PT arrays in edit mode */
|
|
161
|
+
export interface EditFieldMeta {
|
|
162
|
+
collection: string;
|
|
163
|
+
id: string;
|
|
164
|
+
field: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Type guard for EditFieldMeta */
|
|
168
|
+
function isEditFieldMeta(value: unknown): value is EditFieldMeta {
|
|
169
|
+
if (typeof value !== "object" || value === null) return false;
|
|
170
|
+
if (!("collection" in value) || !("id" in value) || !("field" in value)) return false;
|
|
171
|
+
// After `in` checks, TS narrows to Record<"collection" | "id" | "field", unknown>
|
|
172
|
+
const { collection, id, field } = value;
|
|
173
|
+
return typeof collection === "string" && typeof id === "string" && typeof field === "string";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Read edit metadata from a value (returns undefined if not tagged).
|
|
178
|
+
* Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
|
|
179
|
+
* without an unsafe type assertion.
|
|
180
|
+
*/
|
|
181
|
+
export function getEditMeta(value: unknown): EditFieldMeta | undefined {
|
|
182
|
+
if (value && typeof value === "object") {
|
|
183
|
+
const desc = Object.getOwnPropertyDescriptor(value, EMDASH_EDIT);
|
|
184
|
+
const meta: unknown = desc?.value;
|
|
185
|
+
if (isEditFieldMeta(meta)) {
|
|
186
|
+
return meta;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Tag PT-like arrays in entry data with edit metadata (non-enumerable).
|
|
194
|
+
* A PT array is identified by: is an array, first element has _type property.
|
|
195
|
+
*/
|
|
196
|
+
function tagEditableFields(data: Record<string, unknown>, collection: string, id: string): void {
|
|
197
|
+
for (const [field, value] of Object.entries(data)) {
|
|
198
|
+
if (
|
|
199
|
+
Array.isArray(value) &&
|
|
200
|
+
value.length > 0 &&
|
|
201
|
+
value[0] &&
|
|
202
|
+
typeof value[0] === "object" &&
|
|
203
|
+
"_type" in value[0]
|
|
204
|
+
) {
|
|
205
|
+
Object.defineProperty(value, EMDASH_EDIT, {
|
|
206
|
+
value: { collection, id, field } satisfies EditFieldMeta,
|
|
207
|
+
enumerable: false,
|
|
208
|
+
configurable: true,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Safely read a string field from a Record, with optional fallback */
|
|
215
|
+
function dataStr(data: Record<string, unknown>, key: string, fallback = ""): string {
|
|
216
|
+
const val = data[key];
|
|
217
|
+
return typeof val === "string" ? val : fallback;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Type guard for Record<string, unknown> */
|
|
221
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
222
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Extract data as Record from an Astro entry (which is any-typed) */
|
|
226
|
+
function entryData(entry: { data?: unknown }): Record<string, unknown> {
|
|
227
|
+
return isRecord(entry.data) ? entry.data : {};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Extract the database ID from entry data (data.id is the ULID, entry.id is the slug) */
|
|
231
|
+
function entryDatabaseId(entry: { id: string; data?: unknown }): string {
|
|
232
|
+
const d = entryData(entry);
|
|
233
|
+
return dataStr(d, "id") || entry.id;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Extract edit options from entry data for the proxy */
|
|
237
|
+
function entryEditOptions(entry: { data?: unknown }): EditableOptions {
|
|
238
|
+
const data = entryData(entry);
|
|
239
|
+
const status = dataStr(data, "status", "draft");
|
|
240
|
+
const draftRevisionId = dataStr(data, "draftRevisionId") || undefined;
|
|
241
|
+
const liveRevisionId = dataStr(data, "liveRevisionId") || undefined;
|
|
242
|
+
const hasDraft = !!draftRevisionId && draftRevisionId !== liveRevisionId;
|
|
243
|
+
return { status, hasDraft };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get all entries of a content type
|
|
248
|
+
*
|
|
249
|
+
* Returns { entries, error } for graceful error handling.
|
|
250
|
+
*
|
|
251
|
+
* When emdash-env.d.ts is generated, the collection name will be
|
|
252
|
+
* type-checked and the return type will be inferred automatically.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* import { getEmDashCollection } from "emdash";
|
|
257
|
+
*
|
|
258
|
+
* const { entries: posts, error } = await getEmDashCollection("posts");
|
|
259
|
+
* if (error) {
|
|
260
|
+
* console.error("Failed to load posts:", error);
|
|
261
|
+
* return;
|
|
262
|
+
* }
|
|
263
|
+
* // posts[0].data.title is typed (if emdash-env.d.ts exists)
|
|
264
|
+
*
|
|
265
|
+
* // With filters
|
|
266
|
+
* const { entries: drafts } = await getEmDashCollection("posts", { status: "draft" });
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
export async function getEmDashCollection<T extends string, D = InferCollectionData<T>>(
|
|
270
|
+
type: T,
|
|
271
|
+
filter?: CollectionFilter,
|
|
272
|
+
): Promise<CollectionResult<D>> {
|
|
273
|
+
// Dynamic import to avoid build-time issues
|
|
274
|
+
const { getLiveCollection } = await import("astro:content");
|
|
275
|
+
|
|
276
|
+
// Resolve locale: explicit filter > ALS context > defaultLocale (when i18n enabled)
|
|
277
|
+
// Without this, queries return all locale rows, producing broken IDs
|
|
278
|
+
const ctx = getRequestContext();
|
|
279
|
+
const i18nConfig = getI18nConfig();
|
|
280
|
+
const resolvedLocale =
|
|
281
|
+
filter?.locale ?? ctx?.locale ?? (isI18nEnabled() ? i18nConfig!.defaultLocale : undefined);
|
|
282
|
+
|
|
283
|
+
const result = await getLiveCollection(COLLECTION_NAME, {
|
|
284
|
+
type,
|
|
285
|
+
status: filter?.status,
|
|
286
|
+
limit: filter?.limit,
|
|
287
|
+
cursor: filter?.cursor,
|
|
288
|
+
where: filter?.where,
|
|
289
|
+
orderBy: filter?.orderBy,
|
|
290
|
+
locale: resolvedLocale,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const { entries, error, cacheHint } = result;
|
|
294
|
+
// nextCursor is returned by the emdash loader but not part of Astro's base
|
|
295
|
+
// LiveLoader return type. Extract it safely via property descriptor to avoid
|
|
296
|
+
// an unsafe type assertion on the `any`-typed result object.
|
|
297
|
+
const rawCursor = Object.getOwnPropertyDescriptor(result, "nextCursor")?.value;
|
|
298
|
+
const nextCursor: string | undefined = typeof rawCursor === "string" ? rawCursor : undefined;
|
|
299
|
+
|
|
300
|
+
if (error) {
|
|
301
|
+
return { entries: [], error, cacheHint: {} };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const isEditMode = ctx?.editMode ?? false;
|
|
305
|
+
const entriesWithEdit = entries.map((entry: ContentEntry<D>) => {
|
|
306
|
+
const dbId = entryDatabaseId(entry);
|
|
307
|
+
if (isEditMode) {
|
|
308
|
+
tagEditableFields(entryData(entry), type, dbId);
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
...entry,
|
|
312
|
+
edit: isEditMode ? createEditable(type, dbId, entryEditOptions(entry)) : createNoop(),
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Eagerly hydrate bylines for all entries
|
|
317
|
+
await hydrateEntryBylines(type, entriesWithEdit);
|
|
318
|
+
|
|
319
|
+
return { entries: entriesWithEdit, nextCursor, cacheHint: cacheHint ?? {} };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Get a single entry by type and ID/slug
|
|
324
|
+
*
|
|
325
|
+
* Returns { entry, error, isPreview } for graceful error handling.
|
|
326
|
+
* - entry is null if not found (not an error)
|
|
327
|
+
* - error is set only for actual errors (db issues, etc.)
|
|
328
|
+
*
|
|
329
|
+
* Preview mode is detected automatically from request context (ALS).
|
|
330
|
+
* When the URL has a valid `_preview` token, the middleware sets preview
|
|
331
|
+
* context and this function serves draft revision data if available.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* import { getEmDashEntry } from "emdash";
|
|
336
|
+
*
|
|
337
|
+
* // Simple usage — preview just works via middleware
|
|
338
|
+
* const { entry: post, isPreview, error } = await getEmDashEntry("posts", "my-slug");
|
|
339
|
+
* if (!post) return Astro.redirect("/404");
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
export async function getEmDashEntry<T extends string, D = InferCollectionData<T>>(
|
|
343
|
+
type: T,
|
|
344
|
+
id: string,
|
|
345
|
+
options?: { locale?: string },
|
|
346
|
+
): Promise<EntryResult<D>> {
|
|
347
|
+
// Dynamic import to avoid build-time issues
|
|
348
|
+
const { getLiveEntry } = await import("astro:content");
|
|
349
|
+
|
|
350
|
+
// Check ALS for preview and edit mode context
|
|
351
|
+
const ctx = getRequestContext();
|
|
352
|
+
const preview = ctx?.preview;
|
|
353
|
+
const isEditMode = ctx?.editMode ?? false;
|
|
354
|
+
const isPreviewMode = !!preview && preview.collection === type;
|
|
355
|
+
// Edit mode implies preview — editors should see draft content
|
|
356
|
+
const serveDrafts = isPreviewMode || isEditMode;
|
|
357
|
+
|
|
358
|
+
// Resolve locale: explicit option > ALS context > undefined (no filter)
|
|
359
|
+
const requestedLocale = options?.locale ?? ctx?.locale;
|
|
360
|
+
|
|
361
|
+
/** Wrap a raw Astro entry with edit proxy, tagging editable fields if needed */
|
|
362
|
+
function wrapEntry(raw: ContentEntry<D>): ContentEntry<D> {
|
|
363
|
+
const dbId = entryDatabaseId(raw);
|
|
364
|
+
if (isEditMode) {
|
|
365
|
+
tagEditableFields(entryData(raw), type, dbId);
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
...raw,
|
|
369
|
+
edit: isEditMode ? createEditable(type, dbId, entryEditOptions(raw)) : createNoop(),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** Check if an entry is publicly visible (published or scheduled past its time) */
|
|
374
|
+
function isVisible(entry: ContentEntry<D>): boolean {
|
|
375
|
+
const data = entryData(entry);
|
|
376
|
+
const status = dataStr(data, "status");
|
|
377
|
+
const scheduledAt = dataStr(data, "scheduledAt") || undefined;
|
|
378
|
+
const isPublished = status === "published";
|
|
379
|
+
const isScheduledAndReady =
|
|
380
|
+
status === "scheduled" && scheduledAt && new Date(scheduledAt) <= new Date();
|
|
381
|
+
return isPublished || !!isScheduledAndReady;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Build the fallback chain: [requestedLocale, fallback1, ..., defaultLocale]
|
|
385
|
+
// When i18n is disabled or no locale requested, just use a single-element chain
|
|
386
|
+
const localeChain =
|
|
387
|
+
requestedLocale && isI18nEnabled() ? getFallbackChain(requestedLocale) : [requestedLocale];
|
|
388
|
+
|
|
389
|
+
/** Return a successful EntryResult with bylines hydrated */
|
|
390
|
+
async function successResult(
|
|
391
|
+
wrapped: ContentEntry<D>,
|
|
392
|
+
opts: { isPreview: boolean; fallbackLocale?: string; cacheHint: CacheHint },
|
|
393
|
+
): Promise<EntryResult<D>> {
|
|
394
|
+
await hydrateEntryBylines(type, [wrapped]);
|
|
395
|
+
return {
|
|
396
|
+
entry: wrapped,
|
|
397
|
+
isPreview: opts.isPreview,
|
|
398
|
+
fallbackLocale: opts.fallbackLocale,
|
|
399
|
+
cacheHint: opts.cacheHint,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (serveDrafts) {
|
|
404
|
+
// Draft mode: try each locale in the fallback chain
|
|
405
|
+
for (let i = 0; i < localeChain.length; i++) {
|
|
406
|
+
const locale = localeChain[i];
|
|
407
|
+
const fallbackLocale = i > 0 ? locale : undefined;
|
|
408
|
+
|
|
409
|
+
const {
|
|
410
|
+
entry: baseEntry,
|
|
411
|
+
error: baseError,
|
|
412
|
+
cacheHint,
|
|
413
|
+
} = await getLiveEntry(COLLECTION_NAME, {
|
|
414
|
+
type,
|
|
415
|
+
id,
|
|
416
|
+
locale,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
if (baseError) {
|
|
420
|
+
return { entry: null, error: baseError, isPreview: serveDrafts, cacheHint: {} };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!baseEntry) continue; // Try next locale in chain
|
|
424
|
+
|
|
425
|
+
// Check if entry has a draft revision — if so, re-fetch with revision data
|
|
426
|
+
const baseData = entryData(baseEntry);
|
|
427
|
+
const draftRevisionId = dataStr(baseData, "draftRevisionId") || undefined;
|
|
428
|
+
|
|
429
|
+
if (draftRevisionId) {
|
|
430
|
+
const { entry: draftEntry, error: draftError } = await getLiveEntry(COLLECTION_NAME, {
|
|
431
|
+
type,
|
|
432
|
+
id,
|
|
433
|
+
revisionId: draftRevisionId,
|
|
434
|
+
locale,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (!draftError && draftEntry) {
|
|
438
|
+
return successResult(wrapEntry(draftEntry), {
|
|
439
|
+
isPreview: serveDrafts,
|
|
440
|
+
fallbackLocale,
|
|
441
|
+
cacheHint: cacheHint ?? {},
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return successResult(wrapEntry(baseEntry), {
|
|
447
|
+
isPreview: serveDrafts,
|
|
448
|
+
fallbackLocale,
|
|
449
|
+
cacheHint: cacheHint ?? {},
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// No entry found in any locale
|
|
454
|
+
return { entry: null, isPreview: serveDrafts, cacheHint: {} };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Normal mode: try each locale in the fallback chain, only return published content
|
|
458
|
+
for (let i = 0; i < localeChain.length; i++) {
|
|
459
|
+
const locale = localeChain[i];
|
|
460
|
+
const fallbackLocale = i > 0 ? locale : undefined;
|
|
461
|
+
|
|
462
|
+
const { entry, error, cacheHint } = await getLiveEntry(COLLECTION_NAME, { type, id, locale });
|
|
463
|
+
if (error) {
|
|
464
|
+
return { entry: null, error, isPreview: false, cacheHint: {} };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (entry && isVisible(entry)) {
|
|
468
|
+
return successResult(wrapEntry(entry), {
|
|
469
|
+
isPreview: false,
|
|
470
|
+
fallbackLocale,
|
|
471
|
+
cacheHint: cacheHint ?? {},
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
// Entry not found or not visible in this locale — try next
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return { entry: null, isPreview: false, cacheHint: {} };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Eagerly hydrate byline data onto entry.data for one or more entries.
|
|
482
|
+
*
|
|
483
|
+
* Attaches `bylines` (array of ContentBylineCredit) and `byline`
|
|
484
|
+
* (primary BylineSummary or null) to each entry's data object.
|
|
485
|
+
* Uses batch queries to avoid N+1.
|
|
486
|
+
*
|
|
487
|
+
* Fails silently if the byline tables don't exist yet (pre-migration).
|
|
488
|
+
*/
|
|
489
|
+
async function hydrateEntryBylines<D>(type: string, entries: ContentEntry<D>[]): Promise<void> {
|
|
490
|
+
if (entries.length === 0) return;
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
const { getBylinesForEntries } = await import("./bylines/index.js");
|
|
494
|
+
|
|
495
|
+
const ids = entries.map((e) => dataStr(entryData(e), "id")).filter(Boolean);
|
|
496
|
+
if (ids.length === 0) return;
|
|
497
|
+
|
|
498
|
+
const bylinesMap = await getBylinesForEntries(type, ids);
|
|
499
|
+
|
|
500
|
+
for (const entry of entries) {
|
|
501
|
+
const data = entryData(entry);
|
|
502
|
+
const dbId = dataStr(data, "id");
|
|
503
|
+
if (!dbId) continue;
|
|
504
|
+
|
|
505
|
+
const credits = bylinesMap.get(dbId) ?? [];
|
|
506
|
+
data.bylines = credits;
|
|
507
|
+
data.byline = credits[0]?.byline ?? null;
|
|
508
|
+
}
|
|
509
|
+
} catch (err) {
|
|
510
|
+
// Only swallow "table not found" errors from pre-migration databases
|
|
511
|
+
const msg = err instanceof Error ? err.message : "";
|
|
512
|
+
if (!msg.includes("no such table")) {
|
|
513
|
+
console.warn("[emdash] Failed to hydrate bylines:", msg);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Translation summary for a single locale variant
|
|
520
|
+
*/
|
|
521
|
+
export interface TranslationSummary {
|
|
522
|
+
/** Content item ID */
|
|
523
|
+
id: string;
|
|
524
|
+
/** Locale code (e.g. "en", "fr") */
|
|
525
|
+
locale: string;
|
|
526
|
+
/** URL slug */
|
|
527
|
+
slug: string | null;
|
|
528
|
+
/** Current status */
|
|
529
|
+
status: string;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Result from getTranslations
|
|
534
|
+
*/
|
|
535
|
+
export interface TranslationsResult {
|
|
536
|
+
/** The translation group ID (shared across locales) */
|
|
537
|
+
translationGroup: string;
|
|
538
|
+
/** All locale variants in this group */
|
|
539
|
+
translations: TranslationSummary[];
|
|
540
|
+
/** Error if the query failed */
|
|
541
|
+
error?: Error;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Get all translations of a content item.
|
|
546
|
+
*
|
|
547
|
+
* Given a content entry, returns all locale variants that share the same
|
|
548
|
+
* translation group. This is useful for building language switcher UI.
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* ```ts
|
|
552
|
+
* import { getEmDashEntry, getTranslations } from "emdash";
|
|
553
|
+
*
|
|
554
|
+
* const { entry: post } = await getEmDashEntry("posts", "hello-world", { locale: "en" });
|
|
555
|
+
* const { translations } = await getTranslations("posts", post.data.id);
|
|
556
|
+
* // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
|
|
557
|
+
* ```
|
|
558
|
+
*/
|
|
559
|
+
export async function getTranslations(type: string, id: string): Promise<TranslationsResult> {
|
|
560
|
+
try {
|
|
561
|
+
const db = (await import("./loader.js")).getDb;
|
|
562
|
+
const dbInstance = await db();
|
|
563
|
+
const { ContentRepository } = await import("./database/repositories/content.js");
|
|
564
|
+
const repo = new ContentRepository(dbInstance);
|
|
565
|
+
|
|
566
|
+
// Find the item to get its translation group
|
|
567
|
+
const item = await repo.findByIdOrSlug(type, id);
|
|
568
|
+
if (!item) {
|
|
569
|
+
return {
|
|
570
|
+
translationGroup: "",
|
|
571
|
+
translations: [],
|
|
572
|
+
error: new Error(`Content item not found: ${id}`),
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const group = item.translationGroup || item.id;
|
|
577
|
+
const translations = await repo.findTranslations(type, group);
|
|
578
|
+
|
|
579
|
+
return {
|
|
580
|
+
translationGroup: group,
|
|
581
|
+
translations: translations.map((t) => ({
|
|
582
|
+
id: t.id,
|
|
583
|
+
locale: t.locale || "en",
|
|
584
|
+
slug: t.slug,
|
|
585
|
+
status: t.status,
|
|
586
|
+
})),
|
|
587
|
+
};
|
|
588
|
+
} catch (error) {
|
|
589
|
+
return {
|
|
590
|
+
translationGroup: "",
|
|
591
|
+
translations: [],
|
|
592
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Result from resolveEmDashPath
|
|
599
|
+
*/
|
|
600
|
+
export interface ResolvePathResult<T = Record<string, unknown>> {
|
|
601
|
+
/** The matched entry */
|
|
602
|
+
entry: ContentEntry<T>;
|
|
603
|
+
/** The collection slug that matched */
|
|
604
|
+
collection: string;
|
|
605
|
+
/** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
|
|
606
|
+
params: Record<string, string>;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/** Matches `{paramName}` placeholders in URL patterns */
|
|
610
|
+
const URL_PARAM_PATTERN = /\{(\w+)\}/g;
|
|
611
|
+
|
|
612
|
+
/** Convert a URL pattern like "/blog/{slug}" to a regex and param name list */
|
|
613
|
+
function patternToRegex(pattern: string): { regex: RegExp; paramNames: string[] } {
|
|
614
|
+
const paramNames: string[] = [];
|
|
615
|
+
const regexStr = pattern.replace(URL_PARAM_PATTERN, (_match, name: string) => {
|
|
616
|
+
paramNames.push(name);
|
|
617
|
+
return "([^/]+)";
|
|
618
|
+
});
|
|
619
|
+
return { regex: new RegExp(`^${regexStr}$`), paramNames };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Resolve a URL path to a content entry by matching against collection URL patterns.
|
|
624
|
+
*
|
|
625
|
+
* Loads all collections with a `urlPattern` set, converts each pattern to a regex,
|
|
626
|
+
* and tests the given path. On match, extracts the slug and fetches the entry.
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* ```ts
|
|
630
|
+
* import { resolveEmDashPath } from "emdash";
|
|
631
|
+
*
|
|
632
|
+
* // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
|
|
633
|
+
* const result = await resolveEmDashPath("/blog/hello-world");
|
|
634
|
+
* if (result) {
|
|
635
|
+
* console.log(result.collection); // "posts"
|
|
636
|
+
* console.log(result.params.slug); // "hello-world"
|
|
637
|
+
* console.log(result.entry.data); // post data
|
|
638
|
+
* }
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
export async function resolveEmDashPath<T = Record<string, unknown>>(
|
|
642
|
+
path: string,
|
|
643
|
+
): Promise<ResolvePathResult<T> | null> {
|
|
644
|
+
const { getDb } = await import("./loader.js");
|
|
645
|
+
const { SchemaRegistry } = await import("./schema/registry.js");
|
|
646
|
+
const db = await getDb();
|
|
647
|
+
const registry = new SchemaRegistry(db);
|
|
648
|
+
const collections = await registry.listCollections();
|
|
649
|
+
|
|
650
|
+
for (const collection of collections) {
|
|
651
|
+
if (!collection.urlPattern) continue;
|
|
652
|
+
|
|
653
|
+
const { regex, paramNames } = patternToRegex(collection.urlPattern);
|
|
654
|
+
const match = path.match(regex);
|
|
655
|
+
if (!match) continue;
|
|
656
|
+
|
|
657
|
+
// Extract params
|
|
658
|
+
const params: Record<string, string> = {};
|
|
659
|
+
for (let i = 0; i < paramNames.length; i++) {
|
|
660
|
+
params[paramNames[i]] = match[i + 1];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Look up entry by slug (most common pattern)
|
|
664
|
+
const slug = params.slug;
|
|
665
|
+
if (!slug) continue;
|
|
666
|
+
|
|
667
|
+
const { entry } = await getEmDashEntry<string, T>(collection.slug, slug);
|
|
668
|
+
if (entry) {
|
|
669
|
+
return { entry, collection: collection.slug, params };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return null;
|
|
674
|
+
}
|