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,171 @@
|
|
|
1
|
+
import { i as encodeBase64url, n as decodeBase64url } from "./base64-MBPo9ozB.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/preview/tokens.ts
|
|
4
|
+
/**
|
|
5
|
+
* Preview token generation and verification
|
|
6
|
+
*
|
|
7
|
+
* Tokens are compact, URL-safe, and HMAC-signed.
|
|
8
|
+
* Format: base64url(JSON payload).base64url(HMAC signature)
|
|
9
|
+
*
|
|
10
|
+
* Payload: { cid: contentId, exp: expiryTimestamp, iat: issuedAt }
|
|
11
|
+
*/
|
|
12
|
+
const DURATION_PATTERN = /^(\d+)([smhdw])$/;
|
|
13
|
+
/**
|
|
14
|
+
* Parse duration string to seconds
|
|
15
|
+
* Supports: "1h", "30m", "1d", "2w", or raw seconds
|
|
16
|
+
*/
|
|
17
|
+
function parseDuration(duration) {
|
|
18
|
+
if (typeof duration === "number") return duration;
|
|
19
|
+
const match = duration.match(DURATION_PATTERN);
|
|
20
|
+
if (!match) throw new Error(`Invalid duration format: "${duration}". Use "1h", "30m", "1d", "2w", or seconds.`);
|
|
21
|
+
const value = parseInt(match[1], 10);
|
|
22
|
+
const unit = match[2];
|
|
23
|
+
switch (unit) {
|
|
24
|
+
case "s": return value;
|
|
25
|
+
case "m": return value * 60;
|
|
26
|
+
case "h": return value * 60 * 60;
|
|
27
|
+
case "d": return value * 60 * 60 * 24;
|
|
28
|
+
case "w": return value * 60 * 60 * 24 * 7;
|
|
29
|
+
default: throw new Error(`Unknown duration unit: ${unit}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create HMAC-SHA256 signature using Web Crypto API
|
|
34
|
+
*/
|
|
35
|
+
async function createSignature(data, secret) {
|
|
36
|
+
const encoder = new TextEncoder();
|
|
37
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
|
|
38
|
+
name: "HMAC",
|
|
39
|
+
hash: "SHA-256"
|
|
40
|
+
}, false, ["sign"]);
|
|
41
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
42
|
+
return new Uint8Array(signature);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify HMAC-SHA256 signature
|
|
46
|
+
*/
|
|
47
|
+
async function verifySignature(data, signature, secret) {
|
|
48
|
+
const encoder = new TextEncoder();
|
|
49
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
|
|
50
|
+
name: "HMAC",
|
|
51
|
+
hash: "SHA-256"
|
|
52
|
+
}, false, ["verify"]);
|
|
53
|
+
const sigBuffer = new ArrayBuffer(signature.byteLength);
|
|
54
|
+
new Uint8Array(sigBuffer).set(signature);
|
|
55
|
+
return crypto.subtle.verify("HMAC", key, sigBuffer, encoder.encode(data));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Generate a preview token for content
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const token = await generatePreviewToken({
|
|
63
|
+
* contentId: "posts:abc123",
|
|
64
|
+
* expiresIn: "1h",
|
|
65
|
+
* secret: process.env.PREVIEW_SECRET!,
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
async function generatePreviewToken(options) {
|
|
70
|
+
const { contentId, expiresIn = "1h", secret } = options;
|
|
71
|
+
if (!secret) throw new Error("Preview secret is required");
|
|
72
|
+
if (!contentId || !contentId.includes(":")) throw new Error("Content ID must be in format \"collection:id\"");
|
|
73
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
74
|
+
const payload = {
|
|
75
|
+
cid: contentId,
|
|
76
|
+
exp: now + parseDuration(expiresIn),
|
|
77
|
+
iat: now
|
|
78
|
+
};
|
|
79
|
+
const payloadJson = JSON.stringify(payload);
|
|
80
|
+
const encodedPayload = encodeBase64url(new TextEncoder().encode(payloadJson));
|
|
81
|
+
return `${encodedPayload}.${encodeBase64url(await createSignature(encodedPayload, secret))}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Verify a preview token and return the payload
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* // With URL (extracts _preview query param)
|
|
89
|
+
* const result = await verifyPreviewToken({
|
|
90
|
+
* url: Astro.url,
|
|
91
|
+
* secret: import.meta.env.PREVIEW_SECRET,
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* // With token directly
|
|
95
|
+
* const result = await verifyPreviewToken({
|
|
96
|
+
* token: someToken,
|
|
97
|
+
* secret: import.meta.env.PREVIEW_SECRET,
|
|
98
|
+
* });
|
|
99
|
+
*
|
|
100
|
+
* if (result.valid) {
|
|
101
|
+
* console.log(result.payload.cid); // "posts:abc123"
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
async function verifyPreviewToken(options) {
|
|
106
|
+
const { secret } = options;
|
|
107
|
+
if (!secret) throw new Error("Preview secret is required");
|
|
108
|
+
const token = "url" in options ? options.url.searchParams.get("_preview") : options.token;
|
|
109
|
+
if (!token) return {
|
|
110
|
+
valid: false,
|
|
111
|
+
error: "none"
|
|
112
|
+
};
|
|
113
|
+
const parts = token.split(".");
|
|
114
|
+
if (parts.length !== 2) return {
|
|
115
|
+
valid: false,
|
|
116
|
+
error: "malformed"
|
|
117
|
+
};
|
|
118
|
+
const [encodedPayload, encodedSignature] = parts;
|
|
119
|
+
let signature;
|
|
120
|
+
try {
|
|
121
|
+
signature = decodeBase64url(encodedSignature);
|
|
122
|
+
} catch {
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
error: "malformed"
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (!await verifySignature(encodedPayload, signature, secret)) return {
|
|
129
|
+
valid: false,
|
|
130
|
+
error: "invalid"
|
|
131
|
+
};
|
|
132
|
+
let payload;
|
|
133
|
+
try {
|
|
134
|
+
const payloadBytes = decodeBase64url(encodedPayload);
|
|
135
|
+
const payloadJson = new TextDecoder().decode(payloadBytes);
|
|
136
|
+
payload = JSON.parse(payloadJson);
|
|
137
|
+
} catch {
|
|
138
|
+
return {
|
|
139
|
+
valid: false,
|
|
140
|
+
error: "malformed"
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (typeof payload.cid !== "string" || typeof payload.exp !== "number" || typeof payload.iat !== "number") return {
|
|
144
|
+
valid: false,
|
|
145
|
+
error: "malformed"
|
|
146
|
+
};
|
|
147
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
148
|
+
if (payload.exp < now) return {
|
|
149
|
+
valid: false,
|
|
150
|
+
error: "expired"
|
|
151
|
+
};
|
|
152
|
+
return {
|
|
153
|
+
valid: true,
|
|
154
|
+
payload
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse a content ID into collection and id
|
|
159
|
+
*/
|
|
160
|
+
function parseContentId(contentId) {
|
|
161
|
+
const colonIndex = contentId.indexOf(":");
|
|
162
|
+
if (colonIndex === -1) throw new Error("Content ID must be in format \"collection:id\"");
|
|
163
|
+
return {
|
|
164
|
+
collection: contentId.slice(0, colonIndex),
|
|
165
|
+
id: contentId.slice(colonIndex + 1)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { parseContentId as n, verifyPreviewToken as r, generatePreviewToken as t };
|
|
171
|
+
//# sourceMappingURL=tokens-DpgrkrXK.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens-DpgrkrXK.mjs","names":[],"sources":["../src/preview/tokens.ts"],"sourcesContent":["/**\n * Preview token generation and verification\n *\n * Tokens are compact, URL-safe, and HMAC-signed.\n * Format: base64url(JSON payload).base64url(HMAC signature)\n *\n * Payload: { cid: contentId, exp: expiryTimestamp, iat: issuedAt }\n */\n\nimport { encodeBase64url, decodeBase64url } from \"../utils/base64.js\";\n\n// Regex pattern for duration parsing\nconst DURATION_PATTERN = /^(\\d+)([smhdw])$/;\n\n/**\n * Preview token payload\n */\nexport interface PreviewTokenPayload {\n\t/** Content ID in format \"collection:id\" (e.g., \"posts:abc123\") */\n\tcid: string;\n\t/** Expiry timestamp (seconds since epoch) */\n\texp: number;\n\t/** Issued at timestamp (seconds since epoch) */\n\tiat: number;\n}\n\n/**\n * Options for generating a preview token\n */\nexport interface GeneratePreviewTokenOptions {\n\t/** Content ID in format \"collection:id\" */\n\tcontentId: string;\n\t/** How long the token is valid. Accepts \"1h\", \"30m\", \"1d\", or seconds as number. Default: \"1h\" */\n\texpiresIn?: string | number;\n\t/** Secret key for signing. Should be from environment variable. */\n\tsecret: string;\n}\n\n/**\n * Parse duration string to seconds\n * Supports: \"1h\", \"30m\", \"1d\", \"2w\", or raw seconds\n */\nfunction parseDuration(duration: string | number): number {\n\tif (typeof duration === \"number\") {\n\t\treturn duration;\n\t}\n\n\tconst match = duration.match(DURATION_PATTERN);\n\tif (!match) {\n\t\tthrow new Error(\n\t\t\t`Invalid duration format: \"${duration}\". Use \"1h\", \"30m\", \"1d\", \"2w\", or seconds.`,\n\t\t);\n\t}\n\n\tconst value = parseInt(match[1], 10);\n\tconst unit = match[2];\n\n\tswitch (unit) {\n\t\tcase \"s\":\n\t\t\treturn value;\n\t\tcase \"m\":\n\t\t\treturn value * 60;\n\t\tcase \"h\":\n\t\t\treturn value * 60 * 60;\n\t\tcase \"d\":\n\t\t\treturn value * 60 * 60 * 24;\n\t\tcase \"w\":\n\t\t\treturn value * 60 * 60 * 24 * 7;\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown duration unit: ${unit}`);\n\t}\n}\n\n/**\n * Create HMAC-SHA256 signature using Web Crypto API\n */\nasync function createSignature(data: string, secret: string): Promise<Uint8Array> {\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(data));\n\treturn new Uint8Array(signature);\n}\n\n/**\n * Verify HMAC-SHA256 signature\n */\nasync function verifySignature(\n\tdata: string,\n\tsignature: Uint8Array,\n\tsecret: string,\n): Promise<boolean> {\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"verify\"],\n\t);\n\t// Create a new ArrayBuffer from the signature to satisfy BufferSource typing\n\t// (Uint8Array.buffer is ArrayBufferLike which includes SharedArrayBuffer)\n\tconst sigBuffer: ArrayBuffer = new ArrayBuffer(signature.byteLength);\n\tnew Uint8Array(sigBuffer).set(signature);\n\treturn crypto.subtle.verify(\"HMAC\", key, sigBuffer, encoder.encode(data));\n}\n\n/**\n * Generate a preview token for content\n *\n * @example\n * ```ts\n * const token = await generatePreviewToken({\n * contentId: \"posts:abc123\",\n * expiresIn: \"1h\",\n * secret: process.env.PREVIEW_SECRET!,\n * });\n * ```\n */\nexport async function generatePreviewToken(options: GeneratePreviewTokenOptions): Promise<string> {\n\tconst { contentId, expiresIn = \"1h\", secret } = options;\n\n\tif (!secret) {\n\t\tthrow new Error(\"Preview secret is required\");\n\t}\n\n\tif (!contentId || !contentId.includes(\":\")) {\n\t\tthrow new Error('Content ID must be in format \"collection:id\"');\n\t}\n\n\tconst now = Math.floor(Date.now() / 1000);\n\tconst duration = parseDuration(expiresIn);\n\n\tconst payload: PreviewTokenPayload = {\n\t\tcid: contentId,\n\t\texp: now + duration,\n\t\tiat: now,\n\t};\n\n\t// Encode payload\n\tconst payloadJson = JSON.stringify(payload);\n\tconst encodedPayload = encodeBase64url(new TextEncoder().encode(payloadJson));\n\n\t// Sign it\n\tconst signature = await createSignature(encodedPayload, secret);\n\tconst encodedSignature = encodeBase64url(signature);\n\n\treturn `${encodedPayload}.${encodedSignature}`;\n}\n\n/**\n * Result of verifying a preview token\n */\nexport type VerifyPreviewTokenResult =\n\t| { valid: true; payload: PreviewTokenPayload }\n\t| { valid: false; error: \"invalid\" | \"expired\" | \"malformed\" | \"none\" };\n\n/**\n * Options for verifyPreviewToken\n */\nexport type VerifyPreviewTokenOptions = {\n\t/** Secret key for verifying tokens */\n\tsecret: string;\n} & (\n\t| { /** URL to extract _preview token from */ url: URL }\n\t| {\n\t\t\t/** Preview token string (can be null) */ token: string | null | undefined;\n\t }\n);\n\n/**\n * Verify a preview token and return the payload\n *\n * @example\n * ```ts\n * // With URL (extracts _preview query param)\n * const result = await verifyPreviewToken({\n * url: Astro.url,\n * secret: import.meta.env.PREVIEW_SECRET,\n * });\n *\n * // With token directly\n * const result = await verifyPreviewToken({\n * token: someToken,\n * secret: import.meta.env.PREVIEW_SECRET,\n * });\n *\n * if (result.valid) {\n * console.log(result.payload.cid); // \"posts:abc123\"\n * }\n * ```\n */\nexport async function verifyPreviewToken(\n\toptions: VerifyPreviewTokenOptions,\n): Promise<VerifyPreviewTokenResult> {\n\tconst { secret } = options;\n\n\tif (!secret) {\n\t\tthrow new Error(\"Preview secret is required\");\n\t}\n\n\t// Extract token from URL or use provided token\n\tconst token = \"url\" in options ? options.url.searchParams.get(\"_preview\") : options.token;\n\n\t// Handle null/undefined token\n\tif (!token) {\n\t\treturn { valid: false, error: \"none\" };\n\t}\n\n\t// Split token into payload and signature\n\tconst parts = token.split(\".\");\n\tif (parts.length !== 2) {\n\t\treturn { valid: false, error: \"malformed\" };\n\t}\n\n\tconst [encodedPayload, encodedSignature] = parts;\n\n\t// Verify signature\n\tlet signature: Uint8Array;\n\ttry {\n\t\tsignature = decodeBase64url(encodedSignature);\n\t} catch {\n\t\treturn { valid: false, error: \"malformed\" };\n\t}\n\n\tconst isValid = await verifySignature(encodedPayload, signature, secret);\n\tif (!isValid) {\n\t\treturn { valid: false, error: \"invalid\" };\n\t}\n\n\t// Decode and parse payload\n\tlet payload: PreviewTokenPayload;\n\ttry {\n\t\tconst payloadBytes = decodeBase64url(encodedPayload);\n\t\tconst payloadJson = new TextDecoder().decode(payloadBytes);\n\t\tpayload = JSON.parse(payloadJson);\n\t} catch {\n\t\treturn { valid: false, error: \"malformed\" };\n\t}\n\n\t// Check required fields\n\tif (\n\t\ttypeof payload.cid !== \"string\" ||\n\t\ttypeof payload.exp !== \"number\" ||\n\t\ttypeof payload.iat !== \"number\"\n\t) {\n\t\treturn { valid: false, error: \"malformed\" };\n\t}\n\n\t// Check expiry\n\tconst now = Math.floor(Date.now() / 1000);\n\tif (payload.exp < now) {\n\t\treturn { valid: false, error: \"expired\" };\n\t}\n\n\treturn { valid: true, payload };\n}\n\n/**\n * Parse a content ID into collection and id\n */\nexport function parseContentId(contentId: string): {\n\tcollection: string;\n\tid: string;\n} {\n\tconst colonIndex = contentId.indexOf(\":\");\n\tif (colonIndex === -1) {\n\t\tthrow new Error('Content ID must be in format \"collection:id\"');\n\t}\n\treturn {\n\t\tcollection: contentId.slice(0, colonIndex),\n\t\tid: contentId.slice(colonIndex + 1),\n\t};\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,mBAAmB;;;;;AA8BzB,SAAS,cAAc,UAAmC;AACzD,KAAI,OAAO,aAAa,SACvB,QAAO;CAGR,MAAM,QAAQ,SAAS,MAAM,iBAAiB;AAC9C,KAAI,CAAC,MACJ,OAAM,IAAI,MACT,6BAA6B,SAAS,6CACtC;CAGF,MAAM,QAAQ,SAAS,MAAM,IAAI,GAAG;CACpC,MAAM,OAAO,MAAM;AAEnB,SAAQ,MAAR;EACC,KAAK,IACJ,QAAO;EACR,KAAK,IACJ,QAAO,QAAQ;EAChB,KAAK,IACJ,QAAO,QAAQ,KAAK;EACrB,KAAK,IACJ,QAAO,QAAQ,KAAK,KAAK;EAC1B,KAAK,IACJ,QAAO,QAAQ,KAAK,KAAK,KAAK;EAC/B,QACC,OAAM,IAAI,MAAM,0BAA0B,OAAO;;;;;;AAOpD,eAAe,gBAAgB,MAAc,QAAqC;CACjF,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,MAAM,MAAM,OAAO,OAAO,UAC/B,OACA,QAAQ,OAAO,OAAO,EACtB;EAAE,MAAM;EAAQ,MAAM;EAAW,EACjC,OACA,CAAC,OAAO,CACR;CACD,MAAM,YAAY,MAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,QAAQ,OAAO,KAAK,CAAC;AAC7E,QAAO,IAAI,WAAW,UAAU;;;;;AAMjC,eAAe,gBACd,MACA,WACA,QACmB;CACnB,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,MAAM,MAAM,OAAO,OAAO,UAC/B,OACA,QAAQ,OAAO,OAAO,EACtB;EAAE,MAAM;EAAQ,MAAM;EAAW,EACjC,OACA,CAAC,SAAS,CACV;CAGD,MAAM,YAAyB,IAAI,YAAY,UAAU,WAAW;AACpE,KAAI,WAAW,UAAU,CAAC,IAAI,UAAU;AACxC,QAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,WAAW,QAAQ,OAAO,KAAK,CAAC;;;;;;;;;;;;;;AAe1E,eAAsB,qBAAqB,SAAuD;CACjG,MAAM,EAAE,WAAW,YAAY,MAAM,WAAW;AAEhD,KAAI,CAAC,OACJ,OAAM,IAAI,MAAM,6BAA6B;AAG9C,KAAI,CAAC,aAAa,CAAC,UAAU,SAAS,IAAI,CACzC,OAAM,IAAI,MAAM,iDAA+C;CAGhE,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;CAGzC,MAAM,UAA+B;EACpC,KAAK;EACL,KAAK,MAJW,cAAc,UAAU;EAKxC,KAAK;EACL;CAGD,MAAM,cAAc,KAAK,UAAU,QAAQ;CAC3C,MAAM,iBAAiB,gBAAgB,IAAI,aAAa,CAAC,OAAO,YAAY,CAAC;AAM7E,QAAO,GAAG,eAAe,GAFA,gBADP,MAAM,gBAAgB,gBAAgB,OAAO,CACZ;;;;;;;;;;;;;;;;;;;;;;;;AA+CpD,eAAsB,mBACrB,SACoC;CACpC,MAAM,EAAE,WAAW;AAEnB,KAAI,CAAC,OACJ,OAAM,IAAI,MAAM,6BAA6B;CAI9C,MAAM,QAAQ,SAAS,UAAU,QAAQ,IAAI,aAAa,IAAI,WAAW,GAAG,QAAQ;AAGpF,KAAI,CAAC,MACJ,QAAO;EAAE,OAAO;EAAO,OAAO;EAAQ;CAIvC,MAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,KAAI,MAAM,WAAW,EACpB,QAAO;EAAE,OAAO;EAAO,OAAO;EAAa;CAG5C,MAAM,CAAC,gBAAgB,oBAAoB;CAG3C,IAAI;AACJ,KAAI;AACH,cAAY,gBAAgB,iBAAiB;SACtC;AACP,SAAO;GAAE,OAAO;GAAO,OAAO;GAAa;;AAI5C,KAAI,CADY,MAAM,gBAAgB,gBAAgB,WAAW,OAAO,CAEvE,QAAO;EAAE,OAAO;EAAO,OAAO;EAAW;CAI1C,IAAI;AACJ,KAAI;EACH,MAAM,eAAe,gBAAgB,eAAe;EACpD,MAAM,cAAc,IAAI,aAAa,CAAC,OAAO,aAAa;AAC1D,YAAU,KAAK,MAAM,YAAY;SAC1B;AACP,SAAO;GAAE,OAAO;GAAO,OAAO;GAAa;;AAI5C,KACC,OAAO,QAAQ,QAAQ,YACvB,OAAO,QAAQ,QAAQ,YACvB,OAAO,QAAQ,QAAQ,SAEvB,QAAO;EAAE,OAAO;EAAO,OAAO;EAAa;CAI5C,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AACzC,KAAI,QAAQ,MAAM,IACjB,QAAO;EAAE,OAAO;EAAO,OAAO;EAAW;AAG1C,QAAO;EAAE,OAAO;EAAM;EAAS;;;;;AAMhC,SAAgB,eAAe,WAG7B;CACD,MAAM,aAAa,UAAU,QAAQ,IAAI;AACzC,KAAI,eAAe,GAClB,OAAM,IAAI,MAAM,iDAA+C;AAEhE,QAAO;EACN,YAAY,UAAU,MAAM,GAAG,WAAW;EAC1C,IAAI,UAAU,MAAM,aAAa,EAAE;EACnC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/client/transport.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Transport layer for the EmDash client.
|
|
4
|
+
*
|
|
5
|
+
* Implements a composable interceptor pipeline that modifies requests
|
|
6
|
+
* and responses. The client calls `transport.fetch(request)` — everything
|
|
7
|
+
* else (auth, CSRF, retry) is handled by interceptors.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* An interceptor can modify the request, call next(), inspect
|
|
11
|
+
* the response, and optionally retry.
|
|
12
|
+
*/
|
|
13
|
+
type Interceptor = (request: Request, next: (request: Request) => Promise<Response>) => Promise<Response>;
|
|
14
|
+
interface TransportOptions {
|
|
15
|
+
interceptors?: Interceptor[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a fetch function that runs requests through an interceptor pipeline.
|
|
19
|
+
*/
|
|
20
|
+
declare function createTransport(options?: TransportOptions): {
|
|
21
|
+
fetch: (request: Request) => Promise<Response>;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Adds X-EmDash-Request: 1 and Origin headers to mutation requests
|
|
25
|
+
* (POST, PUT, DELETE). The custom header satisfies EmDash's CSRF check;
|
|
26
|
+
* the Origin header satisfies Astro's built-in origin verification which
|
|
27
|
+
* rejects server-side POST requests that lack a matching Origin.
|
|
28
|
+
*/
|
|
29
|
+
declare function csrfInterceptor(): Interceptor;
|
|
30
|
+
/**
|
|
31
|
+
* Adds Authorization: Bearer header from a static token.
|
|
32
|
+
*/
|
|
33
|
+
declare function tokenInterceptor(token: string): Interceptor;
|
|
34
|
+
/**
|
|
35
|
+
* Dev bypass interceptor. Calls the dev-bypass endpoint on first request
|
|
36
|
+
* to establish a session, then forwards the session cookie on subsequent
|
|
37
|
+
* requests.
|
|
38
|
+
*/
|
|
39
|
+
declare function devBypassInterceptor(baseUrl: string): Interceptor;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { tokenInterceptor as a, devBypassInterceptor as i, createTransport as n, csrfInterceptor as r, Interceptor as t };
|
|
42
|
+
//# sourceMappingURL=transport-BFGblqwG.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-BFGblqwG.d.mts","names":[],"sources":["../src/client/transport.ts"],"mappings":";;AAeA;;;;;;;;;;KAAY,WAAA,IACX,OAAA,EAAS,OAAA,EACT,IAAA,GAAO,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA,MAChC,OAAA,CAAQ,QAAA;AAAA,UAEI,gBAAA;EAChB,YAAA,GAAe,WAAA;AAAA;;;;iBAUA,eAAA,CAAgB,OAAA,GAAS,gBAAA;EACxC,KAAA,GAAQ,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;AAAA;;;AAZtC;;;;iBAqCgB,eAAA,CAAA,GAAmB,WAAA;AA1BnC;;;AAAA,iBA8CgB,gBAAA,CAAiB,KAAA,WAAgB,WAAA;;;;;;iBAajC,oBAAA,CAAqB,OAAA,WAAkB,WAAA"}
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
//#region src/client/portable-text.ts
|
|
2
|
+
/**
|
|
3
|
+
* Convert Portable Text blocks to Markdown.
|
|
4
|
+
* Unknown block types are serialized as opaque fences.
|
|
5
|
+
*/
|
|
6
|
+
function portableTextToMarkdown(blocks) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
let prevWasList = false;
|
|
9
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
10
|
+
const block = blocks[i];
|
|
11
|
+
if (block._type === "block") {
|
|
12
|
+
const isList = !!block.listItem;
|
|
13
|
+
if (i > 0 && (!isList || !prevWasList)) lines.push("");
|
|
14
|
+
lines.push(renderStandardBlock(block));
|
|
15
|
+
prevWasList = isList;
|
|
16
|
+
} else if (block._type === "code") {
|
|
17
|
+
if (i > 0) lines.push("");
|
|
18
|
+
const lang = block.language || "";
|
|
19
|
+
const code = block.code || "";
|
|
20
|
+
lines.push("```" + lang);
|
|
21
|
+
lines.push(code);
|
|
22
|
+
lines.push("```");
|
|
23
|
+
prevWasList = false;
|
|
24
|
+
} else if (block._type === "image") {
|
|
25
|
+
if (i > 0) lines.push("");
|
|
26
|
+
const alt = block.alt || "";
|
|
27
|
+
const url = block.asset?.url || "";
|
|
28
|
+
lines.push(``);
|
|
29
|
+
prevWasList = false;
|
|
30
|
+
} else {
|
|
31
|
+
if (i > 0) lines.push("");
|
|
32
|
+
lines.push(`<!--ec:block ${JSON.stringify(block)} -->`);
|
|
33
|
+
prevWasList = false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return lines.join("\n") + "\n";
|
|
37
|
+
}
|
|
38
|
+
function renderStandardBlock(block) {
|
|
39
|
+
const text = renderSpans(block.children ?? [], block.markDefs ?? []);
|
|
40
|
+
if (block.listItem) return `${" ".repeat(Math.max(0, (block.level ?? 1) - 1))}${block.listItem === "number" ? "1." : "-"} ${text}`;
|
|
41
|
+
if (block.style && block.style.startsWith("h")) {
|
|
42
|
+
const level = parseInt(block.style.substring(1), 10);
|
|
43
|
+
if (level >= 1 && level <= 6) return `${"#".repeat(level)} ${text}`;
|
|
44
|
+
}
|
|
45
|
+
if (block.style === "blockquote") return `> ${text}`;
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
function renderSpans(spans, markDefs) {
|
|
49
|
+
let result = "";
|
|
50
|
+
for (const span of spans) {
|
|
51
|
+
if (span._type !== "span") continue;
|
|
52
|
+
let text = span.text ?? "";
|
|
53
|
+
const marks = span.marks ?? [];
|
|
54
|
+
for (const mark of marks) {
|
|
55
|
+
const def = markDefs.find((d) => d._key === mark);
|
|
56
|
+
if (def) {
|
|
57
|
+
if (def._type === "link") text = `[${text}](${def.href ?? ""})`;
|
|
58
|
+
} else switch (mark) {
|
|
59
|
+
case "strong":
|
|
60
|
+
text = `**${text}**`;
|
|
61
|
+
break;
|
|
62
|
+
case "em":
|
|
63
|
+
text = `_${text}_`;
|
|
64
|
+
break;
|
|
65
|
+
case "code":
|
|
66
|
+
text = `\`${text}\``;
|
|
67
|
+
break;
|
|
68
|
+
case "strike-through":
|
|
69
|
+
case "strikethrough":
|
|
70
|
+
text = `~~${text}~~`;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
result += text;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
const OPAQUE_FENCE_PATTERN = /^<!--ec:block (.+) -->$/;
|
|
79
|
+
const HEADING_PATTERN = /^(#{1,6})\s+(.+)$/;
|
|
80
|
+
const UNORDERED_LIST_PATTERN = /^(\s*)[-*+]\s+(.+)$/;
|
|
81
|
+
const ORDERED_LIST_PATTERN = /^(\s*)\d+\.\s+(.+)$/;
|
|
82
|
+
const IMAGE_PATTERN = /^!\[([^\]]*)\]\(([^)]+)\)$/;
|
|
83
|
+
const INLINE_MARKDOWN_PATTERN = /(\*\*(.+?)\*\*)|(_(.+?)_)|(`(.+?)`)|(\[(.+?)\]\((.+?)\))|(~~(.+?)~~)/g;
|
|
84
|
+
/**
|
|
85
|
+
* Convert Markdown to Portable Text blocks.
|
|
86
|
+
* Opaque fences (<!--ec:block ... -->) are deserialized and spliced back in.
|
|
87
|
+
*/
|
|
88
|
+
function markdownToPortableText(markdown) {
|
|
89
|
+
const blocks = [];
|
|
90
|
+
const lines = markdown.split("\n");
|
|
91
|
+
let i = 0;
|
|
92
|
+
while (i < lines.length) {
|
|
93
|
+
const line = lines[i];
|
|
94
|
+
const opaqueMatch = line.match(OPAQUE_FENCE_PATTERN);
|
|
95
|
+
if (opaqueMatch) {
|
|
96
|
+
try {
|
|
97
|
+
blocks.push(JSON.parse(opaqueMatch[1]));
|
|
98
|
+
} catch {
|
|
99
|
+
blocks.push(makeBlock(line));
|
|
100
|
+
}
|
|
101
|
+
i++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (line.startsWith("```")) {
|
|
105
|
+
const lang = line.slice(3).trim();
|
|
106
|
+
const codeLines = [];
|
|
107
|
+
i++;
|
|
108
|
+
while (i < lines.length && !lines[i].startsWith("```")) {
|
|
109
|
+
codeLines.push(lines[i]);
|
|
110
|
+
i++;
|
|
111
|
+
}
|
|
112
|
+
blocks.push({
|
|
113
|
+
_type: "code",
|
|
114
|
+
_key: generateKey(),
|
|
115
|
+
language: lang || void 0,
|
|
116
|
+
code: codeLines.join("\n")
|
|
117
|
+
});
|
|
118
|
+
i++;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (line.trim() === "") {
|
|
122
|
+
i++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const headingMatch = line.match(HEADING_PATTERN);
|
|
126
|
+
if (headingMatch) {
|
|
127
|
+
blocks.push(makeBlock(headingMatch[2], `h${headingMatch[1].length}`));
|
|
128
|
+
i++;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (line.startsWith("> ")) {
|
|
132
|
+
blocks.push(makeBlock(line.slice(2), "blockquote"));
|
|
133
|
+
i++;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const ulMatch = line.match(UNORDERED_LIST_PATTERN);
|
|
137
|
+
if (ulMatch) {
|
|
138
|
+
const level = Math.floor(ulMatch[1].length / 2) + 1;
|
|
139
|
+
blocks.push(makeListBlock(ulMatch[2], "bullet", level));
|
|
140
|
+
i++;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const olMatch = line.match(ORDERED_LIST_PATTERN);
|
|
144
|
+
if (olMatch) {
|
|
145
|
+
const level = Math.floor(olMatch[1].length / 2) + 1;
|
|
146
|
+
blocks.push(makeListBlock(olMatch[2], "number", level));
|
|
147
|
+
i++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const imgMatch = line.match(IMAGE_PATTERN);
|
|
151
|
+
if (imgMatch) {
|
|
152
|
+
blocks.push({
|
|
153
|
+
_type: "image",
|
|
154
|
+
_key: generateKey(),
|
|
155
|
+
alt: imgMatch[1],
|
|
156
|
+
asset: { url: imgMatch[2] }
|
|
157
|
+
});
|
|
158
|
+
i++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
blocks.push(makeBlock(line));
|
|
162
|
+
i++;
|
|
163
|
+
}
|
|
164
|
+
return blocks;
|
|
165
|
+
}
|
|
166
|
+
function makeBlock(text, style = "normal") {
|
|
167
|
+
const { spans, markDefs } = parseInline(text);
|
|
168
|
+
return {
|
|
169
|
+
_type: "block",
|
|
170
|
+
_key: generateKey(),
|
|
171
|
+
style,
|
|
172
|
+
markDefs,
|
|
173
|
+
children: spans
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function makeListBlock(text, listItem, level) {
|
|
177
|
+
const { spans, markDefs } = parseInline(text);
|
|
178
|
+
return {
|
|
179
|
+
_type: "block",
|
|
180
|
+
_key: generateKey(),
|
|
181
|
+
style: "normal",
|
|
182
|
+
listItem,
|
|
183
|
+
level,
|
|
184
|
+
markDefs,
|
|
185
|
+
children: spans
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Parse inline markdown (bold, italic, code, links, strikethrough) into PT spans + markDefs.
|
|
190
|
+
*/
|
|
191
|
+
function parseInline(text) {
|
|
192
|
+
const spans = [];
|
|
193
|
+
const markDefs = [];
|
|
194
|
+
const regex = INLINE_MARKDOWN_PATTERN;
|
|
195
|
+
let lastIndex = 0;
|
|
196
|
+
let match;
|
|
197
|
+
while ((match = regex.exec(text)) !== null) {
|
|
198
|
+
if (match.index > lastIndex) spans.push({
|
|
199
|
+
_type: "span",
|
|
200
|
+
_key: generateKey(),
|
|
201
|
+
text: text.slice(lastIndex, match.index),
|
|
202
|
+
marks: []
|
|
203
|
+
});
|
|
204
|
+
if (match[2] != null) spans.push({
|
|
205
|
+
_type: "span",
|
|
206
|
+
_key: generateKey(),
|
|
207
|
+
text: match[2],
|
|
208
|
+
marks: ["strong"]
|
|
209
|
+
});
|
|
210
|
+
else if (match[4] != null) spans.push({
|
|
211
|
+
_type: "span",
|
|
212
|
+
_key: generateKey(),
|
|
213
|
+
text: match[4],
|
|
214
|
+
marks: ["em"]
|
|
215
|
+
});
|
|
216
|
+
else if (match[6] != null) spans.push({
|
|
217
|
+
_type: "span",
|
|
218
|
+
_key: generateKey(),
|
|
219
|
+
text: match[6],
|
|
220
|
+
marks: ["code"]
|
|
221
|
+
});
|
|
222
|
+
else if (match[8] != null && match[9] != null) {
|
|
223
|
+
const key = generateKey();
|
|
224
|
+
markDefs.push({
|
|
225
|
+
_key: key,
|
|
226
|
+
_type: "link",
|
|
227
|
+
href: match[9]
|
|
228
|
+
});
|
|
229
|
+
spans.push({
|
|
230
|
+
_type: "span",
|
|
231
|
+
_key: generateKey(),
|
|
232
|
+
text: match[8],
|
|
233
|
+
marks: [key]
|
|
234
|
+
});
|
|
235
|
+
} else if (match[11] != null) spans.push({
|
|
236
|
+
_type: "span",
|
|
237
|
+
_key: generateKey(),
|
|
238
|
+
text: match[11],
|
|
239
|
+
marks: ["strike-through"]
|
|
240
|
+
});
|
|
241
|
+
lastIndex = match.index + match[0].length;
|
|
242
|
+
}
|
|
243
|
+
if (lastIndex < text.length) spans.push({
|
|
244
|
+
_type: "span",
|
|
245
|
+
_key: generateKey(),
|
|
246
|
+
text: text.slice(lastIndex),
|
|
247
|
+
marks: []
|
|
248
|
+
});
|
|
249
|
+
if (spans.length === 0) spans.push({
|
|
250
|
+
_type: "span",
|
|
251
|
+
_key: generateKey(),
|
|
252
|
+
text,
|
|
253
|
+
marks: []
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
spans,
|
|
257
|
+
markDefs
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
let keyCounter = 0;
|
|
261
|
+
function generateKey() {
|
|
262
|
+
return `k${(keyCounter++).toString(36)}`;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Convert content data for reading: PT fields -> markdown strings.
|
|
266
|
+
* Only converts fields with type "portableText" that contain arrays.
|
|
267
|
+
*/
|
|
268
|
+
function convertDataForRead(data, fields, raw = false) {
|
|
269
|
+
if (raw) return data;
|
|
270
|
+
const result = { ...data };
|
|
271
|
+
for (const field of fields) if (field.type === "portableText" && Array.isArray(result[field.slug])) result[field.slug] = portableTextToMarkdown(result[field.slug]);
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Convert content data for writing: markdown strings -> PT arrays.
|
|
276
|
+
* Only converts fields with type "portableText" that contain strings.
|
|
277
|
+
*/
|
|
278
|
+
function convertDataForWrite(data, fields) {
|
|
279
|
+
const result = { ...data };
|
|
280
|
+
for (const field of fields) if (field.type === "portableText" && typeof result[field.slug] === "string") result[field.slug] = markdownToPortableText(result[field.slug]);
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/client/transport.ts
|
|
286
|
+
/**
|
|
287
|
+
* Transport layer for the EmDash client.
|
|
288
|
+
*
|
|
289
|
+
* Implements a composable interceptor pipeline that modifies requests
|
|
290
|
+
* and responses. The client calls `transport.fetch(request)` — everything
|
|
291
|
+
* else (auth, CSRF, retry) is handled by interceptors.
|
|
292
|
+
*/
|
|
293
|
+
const COOKIE_NAME_VALUE_PATTERN = /^([^;]+)/;
|
|
294
|
+
function baseFetch(request) {
|
|
295
|
+
return globalThis.fetch(request);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Creates a fetch function that runs requests through an interceptor pipeline.
|
|
299
|
+
*/
|
|
300
|
+
function createTransport(options = {}) {
|
|
301
|
+
const interceptors = options.interceptors ?? [];
|
|
302
|
+
let chain = baseFetch;
|
|
303
|
+
for (let i = interceptors.length - 1; i >= 0; i--) {
|
|
304
|
+
const interceptor = interceptors[i];
|
|
305
|
+
const next = chain;
|
|
306
|
+
chain = (req) => interceptor(req, next);
|
|
307
|
+
}
|
|
308
|
+
return { fetch: chain };
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Adds X-EmDash-Request: 1 and Origin headers to mutation requests
|
|
312
|
+
* (POST, PUT, DELETE). The custom header satisfies EmDash's CSRF check;
|
|
313
|
+
* the Origin header satisfies Astro's built-in origin verification which
|
|
314
|
+
* rejects server-side POST requests that lack a matching Origin.
|
|
315
|
+
*/
|
|
316
|
+
function csrfInterceptor() {
|
|
317
|
+
const MUTATION_METHODS = new Set([
|
|
318
|
+
"POST",
|
|
319
|
+
"PUT",
|
|
320
|
+
"DELETE",
|
|
321
|
+
"PATCH"
|
|
322
|
+
]);
|
|
323
|
+
return (request, next) => {
|
|
324
|
+
if (MUTATION_METHODS.has(request.method)) {
|
|
325
|
+
const headers = new Headers(request.headers);
|
|
326
|
+
headers.set("X-EmDash-Request", "1");
|
|
327
|
+
if (!headers.has("Origin")) {
|
|
328
|
+
const url = new URL(request.url);
|
|
329
|
+
headers.set("Origin", url.origin);
|
|
330
|
+
}
|
|
331
|
+
return next(new Request(request, { headers }));
|
|
332
|
+
}
|
|
333
|
+
return next(request);
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Adds Authorization: Bearer header from a static token.
|
|
338
|
+
*/
|
|
339
|
+
function tokenInterceptor(token) {
|
|
340
|
+
return (request, next) => {
|
|
341
|
+
const headers = new Headers(request.headers);
|
|
342
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
343
|
+
return next(new Request(request, { headers }));
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Dev bypass interceptor. Calls the dev-bypass endpoint on first request
|
|
348
|
+
* to establish a session, then forwards the session cookie on subsequent
|
|
349
|
+
* requests.
|
|
350
|
+
*/
|
|
351
|
+
function devBypassInterceptor(baseUrl) {
|
|
352
|
+
let sessionCookie = null;
|
|
353
|
+
let initializing = null;
|
|
354
|
+
async function init() {
|
|
355
|
+
const bypassUrl = new URL("/_emdash/api/auth/dev-bypass", baseUrl);
|
|
356
|
+
const res = await globalThis.fetch(bypassUrl, { redirect: "manual" });
|
|
357
|
+
const setCookie = res.headers.get("set-cookie");
|
|
358
|
+
if (setCookie) {
|
|
359
|
+
const match = setCookie.match(COOKIE_NAME_VALUE_PATTERN);
|
|
360
|
+
if (match) sessionCookie = match[1];
|
|
361
|
+
}
|
|
362
|
+
if (res.body) await res.text().catch(() => {});
|
|
363
|
+
}
|
|
364
|
+
return async (request, next) => {
|
|
365
|
+
if (!sessionCookie) {
|
|
366
|
+
if (!initializing) initializing = init();
|
|
367
|
+
await initializing;
|
|
368
|
+
}
|
|
369
|
+
if (sessionCookie) {
|
|
370
|
+
const headers = new Headers(request.headers);
|
|
371
|
+
const existing = headers.get("cookie");
|
|
372
|
+
headers.set("cookie", existing ? `${existing}; ${sessionCookie}` : sessionCookie);
|
|
373
|
+
return next(new Request(request, { headers }));
|
|
374
|
+
}
|
|
375
|
+
return next(request);
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Auto-refreshes expired OAuth tokens on 401 responses.
|
|
380
|
+
* Requires a refresh token and the token endpoint URL.
|
|
381
|
+
*/
|
|
382
|
+
function refreshInterceptor(options) {
|
|
383
|
+
let refreshing = null;
|
|
384
|
+
async function refresh() {
|
|
385
|
+
const res = await globalThis.fetch(options.tokenEndpoint, {
|
|
386
|
+
method: "POST",
|
|
387
|
+
headers: { "Content-Type": "application/json" },
|
|
388
|
+
body: JSON.stringify({
|
|
389
|
+
grant_type: "refresh_token",
|
|
390
|
+
refresh_token: options.refreshToken
|
|
391
|
+
})
|
|
392
|
+
});
|
|
393
|
+
if (!res.ok) return null;
|
|
394
|
+
const data = await res.json();
|
|
395
|
+
const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1e3).toISOString() : new Date(Date.now() + 36e5).toISOString();
|
|
396
|
+
if (options.onTokenRefreshed) options.onTokenRefreshed(data.access_token, data.refresh_token ?? options.refreshToken, expiresAt);
|
|
397
|
+
return data.access_token;
|
|
398
|
+
}
|
|
399
|
+
return async (request, next) => {
|
|
400
|
+
const response = await next(request);
|
|
401
|
+
if (response.status === 401) {
|
|
402
|
+
if (!refreshing) refreshing = refresh().finally(() => {
|
|
403
|
+
refreshing = null;
|
|
404
|
+
});
|
|
405
|
+
const newToken = await refreshing;
|
|
406
|
+
if (newToken) {
|
|
407
|
+
const headers = new Headers(request.headers);
|
|
408
|
+
headers.set("Authorization", `Bearer ${newToken}`);
|
|
409
|
+
return next(new Request(request, { headers }));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return response;
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
//#endregion
|
|
417
|
+
export { tokenInterceptor as a, markdownToPortableText as c, refreshInterceptor as i, portableTextToMarkdown as l, csrfInterceptor as n, convertDataForRead as o, devBypassInterceptor as r, convertDataForWrite as s, createTransport as t };
|
|
418
|
+
//# sourceMappingURL=transport-yxiQsi8I.mjs.map
|