emdash 0.37.0 → 0.39.0
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/dist/action-token-On1sot_c.mjs +26 -0
- package/dist/action-token-On1sot_c.mjs.map +1 -0
- package/dist/activation-CaMfdBt1.mjs +382 -0
- package/dist/activation-CaMfdBt1.mjs.map +1 -0
- package/dist/adapters-Cq10K4_c.d.mts +171 -0
- package/dist/adapters-Cq10K4_c.d.mts.map +1 -0
- package/dist/after-PcEvMY_6.mjs +96 -0
- package/dist/after-PcEvMY_6.mjs.map +1 -0
- package/dist/allowed-origins-1Sa-2wZK.mjs +116 -0
- package/dist/allowed-origins-1Sa-2wZK.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +4 -3
- package/dist/api/route-utils.d.mts.map +1 -1
- package/dist/api/route-utils.mjs +45 -29
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +7 -6
- package/dist/api-DmjKxPCY.mjs +4831 -0
- package/dist/api-DmjKxPCY.mjs.map +1 -0
- package/dist/api-tokens-BIXItFKV.mjs +163 -0
- package/dist/api-tokens-BIXItFKV.mjs.map +1 -0
- package/dist/apply-drpfmqrR.mjs +1005 -0
- package/dist/apply-drpfmqrR.mjs.map +1 -0
- package/dist/artifact-fetch-COiMhVgk.mjs +813 -0
- package/dist/artifact-fetch-COiMhVgk.mjs.map +1 -0
- package/dist/astro/index.d.mts +14 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +123 -13
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +12 -10
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +20 -11
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +11 -9
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.d.mts +1 -1
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +154 -28
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +13 -10
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +122 -3041
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +10 -9
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +10 -9
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +13 -12
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +13 -12
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +13 -12
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +22 -21
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +22 -21
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +22 -21
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +21 -54
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/bulk.mjs +15 -14
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/counts.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/index.mjs +15 -14
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +17 -16
- package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +19 -18
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +19 -18
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +17 -17
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +21 -20
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +19 -18
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +19 -18
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +9 -66
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +9 -69
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +66 -59
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +65 -59
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +70 -61
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +87 -63
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +66 -59
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +65 -59
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +85 -63
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +65 -59
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +70 -61
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +90 -66
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -7
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +77 -63
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +67 -61
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +66 -60
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.d.mts +8 -0
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +27 -0
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +65 -59
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +65 -59
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +11 -10
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
- package/dist/astro/routes/api/admin/users/index.mjs +10 -9
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
- package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/complete.mjs +15 -14
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/index.mjs +12 -11
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/register-options.mjs +14 -13
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/logout.mjs +4 -4
- package/dist/astro/routes/api/auth/magic-link/send.mjs +14 -13
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
- package/dist/astro/routes/api/auth/me.mjs +11 -10
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +10 -9
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/options.mjs +16 -15
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +14 -13
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +15 -14
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/verify.mjs +15 -14
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/complete.mjs +15 -14
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/request.mjs +14 -13
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts.map +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +15 -211
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -17
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -11
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts +10 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +67 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +35 -0
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +16 -15
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts +9 -2
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +28 -16
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +27 -23
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +27 -23
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +27 -12
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +23 -20
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +25 -12
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +27 -14
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/index.mjs +18 -12
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
- package/dist/astro/routes/api/dashboard.mjs +14 -12
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +4 -4
- package/dist/astro/routes/api/health.d.mts +8 -0
- package/dist/astro/routes/api/health.d.mts.map +1 -0
- package/dist/astro/routes/api/health.mjs +21 -0
- package/dist/astro/routes/api/health.mjs.map +1 -0
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +25 -23
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -11
- package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/execute.mjs +20 -19
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -10
- package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +15 -14
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +14 -13
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +18 -17
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +25 -23
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +36 -33
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +17 -9
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.d.mts.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +192 -110
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +15 -14
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/replace.mjs +12 -11
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/upload.mjs +8 -8
- package/dist/astro/routes/api/media/_id_/usage.mjs +23 -22
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +22 -21
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/asset/_id_/_filename_.d.mts +8 -0
- package/dist/astro/routes/api/media/asset/_id_/_filename_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +52 -0
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs.map +1 -0
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
- package/dist/astro/routes/api/media/folders/_id_.mjs +12 -11
- package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/folders/index.mjs +12 -11
- package/dist/astro/routes/api/media/folders/index.mjs.map +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
- package/dist/astro/routes/api/media/providers/index.mjs +4 -4
- package/dist/astro/routes/api/media/upload-url.mjs +14 -13
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +26 -25
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +15 -14
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -14
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -14
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +15 -14
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +15 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -14
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
- package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
- package/dist/astro/routes/api/oauth/register.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
- package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
- package/dist/astro/routes/api/oauth/token.mjs +7 -7
- package/dist/astro/routes/api/openapi.json.mjs +95 -24
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts +2 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +22 -40
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/index.mjs +18 -14
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +18 -14
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +20 -22
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.d.mts.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +19 -19
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/index.mjs +27 -23
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +21 -18
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +27 -23
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +65 -59
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +16 -14
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +65 -59
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +65 -59
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +16 -14
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +17 -14
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +16 -14
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +10 -9
- package/dist/astro/routes/api/search/stats.mjs.map +1 -1
- package/dist/astro/routes/api/search/suggest.mjs +15 -13
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +15 -13
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +15 -13
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +9 -8
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +8 -7
- package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/export.mjs +9 -8
- package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/index.mjs +10 -9
- package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +6 -6
- package/dist/astro/routes/api/settings.mjs +22 -20
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +16 -15
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin.mjs +15 -14
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +42 -38
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
- package/dist/astro/routes/api/setup/index.mjs +43 -38
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +5 -5
- package/dist/astro/routes/api/snapshot.mjs +11 -10
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -20
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +23 -21
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +8 -8
- package/dist/astro/routes/api/typegen.mjs +6 -6
- package/dist/astro/routes/api/visual-editing/action-token.d.mts +8 -0
- package/dist/astro/routes/api/visual-editing/action-token.d.mts.map +1 -0
- package/dist/astro/routes/api/visual-editing/action-token.mjs +25 -0
- package/dist/astro/routes/api/visual-editing/action-token.mjs.map +1 -0
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.d.mts +8 -0
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.d.mts.map +1 -0
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +37 -0
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs.map +1 -0
- package/dist/astro/routes/api/visual-editing/toolbar-labels.d.mts +8 -0
- package/dist/astro/routes/api/visual-editing/toolbar-labels.d.mts.map +1 -0
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +20 -0
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs.map +1 -0
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +12 -11
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +16 -15
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +16 -15
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/index.mjs +16 -15
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +4 -4
- package/dist/astro/routes/robots.txt.mjs +13 -12
- package/dist/astro/routes/robots.txt.mjs.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +24 -19
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +14 -13
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +79 -26
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/authoritative-records-DbqshfKD.mjs +5172 -0
- package/dist/authoritative-records-DbqshfKD.mjs.map +1 -0
- package/dist/authorize-BXpfMpp0.mjs +40 -0
- package/dist/authorize-BXpfMpp0.mjs.map +1 -0
- package/dist/backup-BsPQdwnS.mjs +246 -0
- package/dist/backup-BsPQdwnS.mjs.map +1 -0
- package/dist/base64-DvnNgP7e.mjs +63 -0
- package/dist/base64-DvnNgP7e.mjs.map +1 -0
- package/dist/byline-Doh-wt99.mjs +906 -0
- package/dist/byline-Doh-wt99.mjs.map +1 -0
- package/dist/byline-fields-CsrdvaLV.mjs +123 -0
- package/dist/byline-fields-CsrdvaLV.mjs.map +1 -0
- package/dist/byline-registry-D6lWzXk6.mjs +406 -0
- package/dist/byline-registry-D6lWzXk6.mjs.map +1 -0
- package/dist/bylines-Cop0hkoy.mjs +214 -0
- package/dist/bylines-Cop0hkoy.mjs.map +1 -0
- package/dist/bylines-kpBzHPr8.mjs +232 -0
- package/dist/bylines-kpBzHPr8.mjs.map +1 -0
- package/dist/cache-B0pOlXdM.mjs +108 -0
- package/dist/cache-B0pOlXdM.mjs.map +1 -0
- package/dist/capture-triggers-gxQxnxrJ.mjs +362 -0
- package/dist/capture-triggers-gxQxnxrJ.mjs.map +1 -0
- package/dist/challenge-store-CkRdSdd8.mjs +51 -0
- package/dist/challenge-store-CkRdSdd8.mjs.map +1 -0
- package/dist/checksum-Bsi2D9M1.mjs +162 -0
- package/dist/checksum-Bsi2D9M1.mjs.map +1 -0
- package/dist/chrome-tags-D7LGB91U.mjs +24 -0
- package/dist/chrome-tags-D7LGB91U.mjs.map +1 -0
- package/dist/chunks-BmWyou79.mjs +25 -0
- package/dist/chunks-BmWyou79.mjs.map +1 -0
- package/dist/cli/index.mjs +921 -106
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +17 -7
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +17 -12
- package/dist/client/index.mjs.map +1 -1
- package/dist/collection-deletion-C3Xixmkx.mjs +436 -0
- package/dist/collection-deletion-C3Xixmkx.mjs.map +1 -0
- package/dist/collection-slugs-cache-D9auiKmI.mjs +85 -0
- package/dist/collection-slugs-cache-D9auiKmI.mjs.map +1 -0
- package/dist/comment-DcT8qdPK.mjs +313 -0
- package/dist/comment-DcT8qdPK.mjs.map +1 -0
- package/dist/comment-reaction-DY5-y8Y5.mjs +85 -0
- package/dist/comment-reaction-DY5-y8Y5.mjs.map +1 -0
- package/dist/comments-B67VRNGw.mjs +204 -0
- package/dist/comments-B67VRNGw.mjs.map +1 -0
- package/dist/comments-BVzzt6x5.mjs +99 -0
- package/dist/comments-BVzzt6x5.mjs.map +1 -0
- package/dist/components-DIl9Qzh6.mjs +108 -0
- package/dist/components-DIl9Qzh6.mjs.map +1 -0
- package/dist/config-B2acLeC5.mjs +242 -0
- package/dist/config-B2acLeC5.mjs.map +1 -0
- package/dist/config-CGVeT8Hc.mjs +73 -0
- package/dist/config-CGVeT8Hc.mjs.map +1 -0
- package/dist/config-D3HhLON3.d.mts +39 -0
- package/dist/config-D3HhLON3.d.mts.map +1 -0
- package/dist/config-DS7e4EZ9.d.mts +6387 -0
- package/dist/config-DS7e4EZ9.d.mts.map +1 -0
- package/dist/content-DZ3B5qtA.mjs +2216 -0
- package/dist/content-DZ3B5qtA.mjs.map +1 -0
- package/dist/content-list-query-CbPdzsna.d.mts +26 -0
- package/dist/content-list-query-CbPdzsna.d.mts.map +1 -0
- package/dist/content-policy-CM4skrNi.mjs +46 -0
- package/dist/content-policy-CM4skrNi.mjs.map +1 -0
- package/dist/content-refresh-BHLHJgyt.mjs +3599 -0
- package/dist/content-refresh-BHLHJgyt.mjs.map +1 -0
- package/dist/content-repair-BVll5WNl.mjs +440 -0
- package/dist/content-repair-BVll5WNl.mjs.map +1 -0
- package/dist/context-B195kjqZ.mjs +1835 -0
- package/dist/context-B195kjqZ.mjs.map +1 -0
- package/dist/cron-BcR3RN4K.mjs +282 -0
- package/dist/cron-BcR3RN4K.mjs.map +1 -0
- package/dist/dashboard-CZD4G7k_.mjs +151 -0
- package/dist/dashboard-CZD4G7k_.mjs.map +1 -0
- package/dist/database/migration-lock.d.mts +37 -0
- package/dist/database/migration-lock.d.mts.map +1 -0
- package/dist/database/migration-lock.mjs +76 -0
- package/dist/database/migration-lock.mjs.map +1 -0
- package/dist/database/pg-migration-lock.d.mts +1 -1
- package/dist/database/pg-migration-lock.mjs +1 -1
- package/dist/database/pg-migration-lock.mjs.map +1 -1
- package/dist/datetime-normalization-PeiEdcRY.mjs +187 -0
- package/dist/datetime-normalization-PeiEdcRY.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +4 -3
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +7 -6
- package/dist/db/libsql-migrations.mjs.map +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +7 -6
- package/dist/db/postgres-migrations.mjs.map +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +7 -6
- package/dist/db/sqlite-migrations.mjs.map +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/db-errors-CBD5yMro.mjs +55 -0
- package/dist/db-errors-CBD5yMro.mjs.map +1 -0
- package/dist/default-BtlxWgh9.mjs +81 -0
- package/dist/default-BtlxWgh9.mjs.map +1 -0
- package/dist/deferred-tasks-Ba9fphlE.d.mts +9 -0
- package/dist/deferred-tasks-Ba9fphlE.d.mts.map +1 -0
- package/dist/dev-typegen-CZaPLl3V.mjs +29 -0
- package/dist/dev-typegen-CZaPLl3V.mjs.map +1 -0
- package/dist/device-flow-3E5l0fpH.mjs +466 -0
- package/dist/device-flow-3E5l0fpH.mjs.map +1 -0
- package/dist/dialect-helpers-CtYdsX4W.mjs +307 -0
- package/dist/dialect-helpers-CtYdsX4W.mjs.map +1 -0
- package/dist/direct-executor-ZI8E01Yt.mjs +104 -0
- package/dist/direct-executor-ZI8E01Yt.mjs.map +1 -0
- package/dist/dist-2hDLsLeq.mjs +810 -0
- package/dist/dist-2hDLsLeq.mjs.map +1 -0
- package/dist/email-console-gc-E3Eqj.mjs +50 -0
- package/dist/email-console-gc-E3Eqj.mjs.map +1 -0
- package/dist/emdash-runtime-DZGinqTL.mjs +4041 -0
- package/dist/emdash-runtime-DZGinqTL.mjs.map +1 -0
- package/dist/enrich-C2Mk0lwE.mjs +194 -0
- package/dist/enrich-C2Mk0lwE.mjs.map +1 -0
- package/dist/entry-lock-D3C99MXS.mjs +1520 -0
- package/dist/entry-lock-D3C99MXS.mjs.map +1 -0
- package/dist/entry-lock-D9rnj2Lu.mjs +163 -0
- package/dist/entry-lock-D9rnj2Lu.mjs.map +1 -0
- package/dist/entry-lock-DX7QkqEg.d.mts +3503 -0
- package/dist/entry-lock-DX7QkqEg.d.mts.map +1 -0
- package/dist/entry-locks-CO_KaoU5.mjs +167 -0
- package/dist/entry-locks-CO_KaoU5.mjs.map +1 -0
- package/dist/error-CCTCskie.mjs +90 -0
- package/dist/error-CCTCskie.mjs.map +1 -0
- package/dist/errors-W3PA8HqB.mjs +447 -0
- package/dist/errors-W3PA8HqB.mjs.map +1 -0
- package/dist/escape-DN4Qmjsl.mjs +9 -0
- package/dist/escape-DN4Qmjsl.mjs.map +1 -0
- package/dist/field-defs-cache-B337z8UJ.mjs +77 -0
- package/dist/field-defs-cache-B337z8UJ.mjs.map +1 -0
- package/dist/focal-point-Gr34o-4o.mjs +23 -0
- package/dist/focal-point-Gr34o-4o.mjs.map +1 -0
- package/dist/fts-manager-DMb0sbIQ.mjs +413 -0
- package/dist/fts-manager-DMb0sbIQ.mjs.map +1 -0
- package/dist/hash-CLVFzWvx.mjs +37 -0
- package/dist/hash-CLVFzWvx.mjs.map +1 -0
- package/dist/hook-result-KY1jq21o.d.mts +31 -0
- package/dist/hook-result-KY1jq21o.d.mts.map +1 -0
- package/dist/hreflang-BgS2FqhH.d.mts +50 -0
- package/dist/hreflang-BgS2FqhH.d.mts.map +1 -0
- package/dist/hreflang-CrJwqoeb.mjs +105 -0
- package/dist/hreflang-CrJwqoeb.mjs.map +1 -0
- package/dist/http-route-dispatch-DAKlanXb.mjs +339 -0
- package/dist/http-route-dispatch-DAKlanXb.mjs.map +1 -0
- package/dist/identity-DRGSHEEr.mjs +35 -0
- package/dist/identity-DRGSHEEr.mjs.map +1 -0
- package/dist/import-DFr5B_hC.mjs +2020 -0
- package/dist/import-DFr5B_hC.mjs.map +1 -0
- package/dist/index-CDwKDkTq.d.mts +623 -0
- package/dist/index-CDwKDkTq.d.mts.map +1 -0
- package/dist/index.d.mts +27 -22
- package/dist/index.mjs +101 -86
- package/dist/init-lock-4eRRB4Le.mjs +56 -0
- package/dist/init-lock-4eRRB4Le.mjs.map +1 -0
- package/dist/install-finalization-5Os-QZ-2.mjs +58 -0
- package/dist/install-finalization-5Os-QZ-2.mjs.map +1 -0
- package/dist/lifecycle-7e-Lt_kX.mjs +25 -0
- package/dist/lifecycle-7e-Lt_kX.mjs.map +1 -0
- package/dist/load-Cu5bvCZh.mjs +28 -0
- package/dist/load-Cu5bvCZh.mjs.map +1 -0
- package/dist/loader-t4TxaFiQ.mjs +1004 -0
- package/dist/loader-t4TxaFiQ.mjs.map +1 -0
- package/dist/manifest-builder-D31UoJCu.mjs +189 -0
- package/dist/manifest-builder-D31UoJCu.mjs.map +1 -0
- package/dist/manifest-schema-Bkh8SeHd.mjs +491 -0
- package/dist/manifest-schema-Bkh8SeHd.mjs.map +1 -0
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +4 -4
- package/dist/media/local-runtime.d.mts +14 -12
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +12 -11
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/media-TBlKCwo7.mjs +334 -0
- package/dist/media-TBlKCwo7.mjs.map +1 -0
- package/dist/media-allowlist-s60eAIf6.mjs +44 -0
- package/dist/media-allowlist-s60eAIf6.mjs.map +1 -0
- package/dist/media-folders-ClIRLUQv.mjs +210 -0
- package/dist/media-folders-ClIRLUQv.mjs.map +1 -0
- package/dist/media-url-DY_ijO3B.mjs +43 -0
- package/dist/media-url-DY_ijO3B.mjs.map +1 -0
- package/dist/media-usage-C4NolTpQ.mjs +1833 -0
- package/dist/media-usage-C4NolTpQ.mjs.map +1 -0
- package/dist/media-usage-activation-CAhmb14O.mjs +78 -0
- package/dist/media-usage-activation-CAhmb14O.mjs.map +1 -0
- package/dist/media-usage-work-Cu5DqewW.mjs +586 -0
- package/dist/media-usage-work-Cu5DqewW.mjs.map +1 -0
- package/dist/media-usage-work-DJr3rOEN.mjs +152 -0
- package/dist/media-usage-work-DJr3rOEN.mjs.map +1 -0
- package/dist/media-usage-write-fence-DW5oHT7q.mjs +42 -0
- package/dist/media-usage-write-fence-DW5oHT7q.mjs.map +1 -0
- package/dist/menus-DbgU9z5Q.mjs +3732 -0
- package/dist/menus-DbgU9z5Q.mjs.map +1 -0
- package/dist/menus-Wy8m5NcH.mjs +753 -0
- package/dist/menus-Wy8m5NcH.mjs.map +1 -0
- package/dist/migrations/index.d.mts +2 -2
- package/dist/migrations/index.d.mts.map +1 -1
- package/dist/migrations/index.mjs +6 -5
- package/dist/mime-CCYRC4r1.mjs +36 -0
- package/dist/mime-CCYRC4r1.mjs.map +1 -0
- package/dist/mode-CkmOhFqj.mjs +23 -0
- package/dist/mode-CkmOhFqj.mjs.map +1 -0
- package/dist/node-sqlite-compat-vpVaILnb.mjs +46 -0
- package/dist/node-sqlite-compat-vpVaILnb.mjs.map +1 -0
- package/dist/normalize-dChXQjwS.mjs +191 -0
- package/dist/normalize-dChXQjwS.mjs.map +1 -0
- package/dist/oauth-authorization-DZ-R-hmx.mjs +274 -0
- package/dist/oauth-authorization-DZ-R-hmx.mjs.map +1 -0
- package/dist/oauth-clients-BMPA8vjl.mjs +266 -0
- package/dist/oauth-clients-BMPA8vjl.mjs.map +1 -0
- package/dist/oauth-state-store-0gIdb48-.mjs +50 -0
- package/dist/oauth-state-store-0gIdb48-.mjs.map +1 -0
- package/dist/oauth-user-lookup-ChVW4UWu.mjs +26 -0
- package/dist/oauth-user-lookup-ChVW4UWu.mjs.map +1 -0
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/object-cache-DlSVbn5Y.mjs +534 -0
- package/dist/object-cache-DlSVbn5Y.mjs.map +1 -0
- package/dist/options-D5WcorD5.mjs +200 -0
- package/dist/options-D5WcorD5.mjs.map +1 -0
- package/dist/options-DAknChnw.d.mts +77 -0
- package/dist/options-DAknChnw.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.d.mts.map +1 -1
- package/dist/page/index.mjs +13 -0
- package/dist/page/index.mjs.map +1 -1
- package/dist/parse-Cr379Av9.mjs +81 -0
- package/dist/parse-Cr379Av9.mjs.map +1 -0
- package/dist/parse-tj9XLNO_.d.mts +165 -0
- package/dist/parse-tj9XLNO_.d.mts.map +1 -0
- package/dist/passkey-config-BD-wMaCf.mjs +46 -0
- package/dist/passkey-config-BD-wMaCf.mjs.map +1 -0
- package/dist/patterns-Do3iqi7N.mjs +145 -0
- package/dist/patterns-Do3iqi7N.mjs.map +1 -0
- package/dist/placeholder-CubPFn_L.d.mts +306 -0
- package/dist/placeholder-CubPFn_L.d.mts.map +1 -0
- package/dist/plugin-test-runtime.d.mts +97 -0
- package/dist/plugin-test-runtime.d.mts.map +1 -0
- package/dist/plugin-test-runtime.mjs +105 -0
- package/dist/plugin-types.d.mts +53 -15
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-types.mjs +18 -1
- package/dist/plugin-types.mjs.map +1 -0
- package/dist/plugin-utils.d.mts +12 -10
- package/dist/plugin-utils.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +12 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +18 -13
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/plugins/host.d.mts +7 -0
- package/dist/plugins/host.mjs +45 -0
- package/dist/plugins/http-wire.d.mts +25 -0
- package/dist/plugins/http-wire.d.mts.map +1 -0
- package/dist/plugins/http-wire.mjs +148 -0
- package/dist/plugins/http-wire.mjs.map +1 -0
- package/dist/plugins/secret-redactor.d.mts +9 -0
- package/dist/plugins/secret-redactor.d.mts.map +1 -0
- package/dist/plugins/secret-redactor.mjs +51 -0
- package/dist/plugins/secret-redactor.mjs.map +1 -0
- package/dist/plugins-DHurtdXQ.mjs +277 -0
- package/dist/plugins-DHurtdXQ.mjs.map +1 -0
- package/dist/policy-lyZnjpwz.mjs +45 -0
- package/dist/policy-lyZnjpwz.mjs.map +1 -0
- package/dist/portable-text-oAwodbPS.mjs +286 -0
- package/dist/portable-text-oAwodbPS.mjs.map +1 -0
- package/dist/preview-Cup2bj8c.mjs +107 -0
- package/dist/preview-Cup2bj8c.mjs.map +1 -0
- package/dist/protocol-C1CNiKX4.d.mts +61 -0
- package/dist/protocol-C1CNiKX4.d.mts.map +1 -0
- package/dist/public-submission-Cs-pFMQK.mjs +245 -0
- package/dist/public-submission-Cs-pFMQK.mjs.map +1 -0
- package/dist/public-url-BWVHsfQv.mjs +101 -0
- package/dist/public-url-BWVHsfQv.mjs.map +1 -0
- package/dist/query-D-lxiOgn.mjs +890 -0
- package/dist/query-D-lxiOgn.mjs.map +1 -0
- package/dist/query-D7kHKOws.mjs +41 -0
- package/dist/query-D7kHKOws.mjs.map +1 -0
- package/dist/rate-limit-CqJn-w4h.mjs +120 -0
- package/dist/rate-limit-CqJn-w4h.mjs.map +1 -0
- package/dist/redirect-BrChFPIu.mjs +17 -0
- package/dist/redirect-BrChFPIu.mjs.map +1 -0
- package/dist/redirect-D2Yo-b6S.mjs +415 -0
- package/dist/redirect-D2Yo-b6S.mjs.map +1 -0
- package/dist/redirects-BCiTaIQ-.mjs +146 -0
- package/dist/redirects-BCiTaIQ-.mjs.map +1 -0
- package/dist/redirects-ByItliuu.mjs +644 -0
- package/dist/redirects-ByItliuu.mjs.map +1 -0
- package/dist/registry/testing.d.mts +14 -0
- package/dist/registry/testing.d.mts.map +1 -0
- package/dist/registry/testing.mjs +255 -0
- package/dist/registry/testing.mjs.map +1 -0
- package/dist/registry-CkuPoZs7.mjs +1222 -0
- package/dist/registry-CkuPoZs7.mjs.map +1 -0
- package/dist/relation-XTAtOpJO.mjs +334 -0
- package/dist/relation-XTAtOpJO.mjs.map +1 -0
- package/dist/relations-B4w-G5U9.mjs +309 -0
- package/dist/relations-B4w-G5U9.mjs.map +1 -0
- package/dist/relations-O63JWBRj.mjs +403 -0
- package/dist/relations-O63JWBRj.mjs.map +1 -0
- package/dist/request-cache-DaMhSQdx.mjs +104 -0
- package/dist/request-cache-DaMhSQdx.mjs.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/request-meta-C8yl_sIs.mjs +141 -0
- package/dist/request-meta-C8yl_sIs.mjs.map +1 -0
- package/dist/resolve-BJIS8wKr.mjs +199 -0
- package/dist/resolve-BJIS8wKr.mjs.map +1 -0
- package/dist/route-wire-D66L2oaZ.mjs +197 -0
- package/dist/route-wire-D66L2oaZ.mjs.map +1 -0
- package/dist/routes-DYsTe-oR.mjs +321 -0
- package/dist/routes-DYsTe-oR.mjs.map +1 -0
- package/dist/runner-3gfxRsJG.d.mts +68 -0
- package/dist/runner-3gfxRsJG.d.mts.map +1 -0
- package/dist/runner-ClrleR8A.mjs +5502 -0
- package/dist/runner-ClrleR8A.mjs.map +1 -0
- package/dist/runtime.d.mts +13 -11
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +6 -5
- package/dist/runtime.mjs.map +1 -1
- package/dist/schema-CPhPM9Do.mjs +420 -0
- package/dist/schema-CPhPM9Do.mjs.map +1 -0
- package/dist/schema-DEERRrKS.mjs +9 -0
- package/dist/schema-DEERRrKS.mjs.map +1 -0
- package/dist/scopes-Bn8_rCSt.mjs +27 -0
- package/dist/scopes-Bn8_rCSt.mjs.map +1 -0
- package/dist/search-lami_Ota.mjs +448 -0
- package/dist/search-lami_Ota.mjs.map +1 -0
- package/dist/secrets-DNgVgz_e.mjs +341 -0
- package/dist/secrets-DNgVgz_e.mjs.map +1 -0
- package/dist/sections-BIpd4Cxf.mjs +346 -0
- package/dist/sections-BIpd4Cxf.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +35 -31
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.d.mts.map +1 -1
- package/dist/seo/index.mjs +27 -26
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-BtU70b7l.mjs +114 -0
- package/dist/seo-BtU70b7l.mjs.map +1 -0
- package/dist/seo-_4qmazxz.mjs +133 -0
- package/dist/seo-_4qmazxz.mjs.map +1 -0
- package/dist/service-Bpy5iTX0.mjs +150 -0
- package/dist/service-Bpy5iTX0.mjs.map +1 -0
- package/dist/session-user-BQeS2Mrb.mjs +51 -0
- package/dist/session-user-BQeS2Mrb.mjs.map +1 -0
- package/dist/settings-DmroR53o.mjs +420 -0
- package/dist/settings-DmroR53o.mjs.map +1 -0
- package/dist/settings-g2F2a3Ub.mjs +51 -0
- package/dist/settings-g2F2a3Ub.mjs.map +1 -0
- package/dist/setup-complete-BrZaXpVV.mjs +26 -0
- package/dist/setup-complete-BrZaXpVV.mjs.map +1 -0
- package/dist/setup-nonce-Cb9-884O.mjs +25 -0
- package/dist/setup-nonce-Cb9-884O.mjs.map +1 -0
- package/dist/single-flight-cache-B5O2qhO1.mjs +104 -0
- package/dist/single-flight-cache-B5O2qhO1.mjs.map +1 -0
- package/dist/site-url-DjhYCaep.mjs +16 -0
- package/dist/site-url-DjhYCaep.mjs.map +1 -0
- package/dist/slugify-T5GHH42D.mjs +17 -0
- package/dist/slugify-T5GHH42D.mjs.map +1 -0
- package/dist/snapshot-C32Xuv3o.mjs +233 -0
- package/dist/snapshot-C32Xuv3o.mjs.map +1 -0
- package/dist/ssrf-Co1GGFZz.mjs +406 -0
- package/dist/ssrf-Co1GGFZz.mjs.map +1 -0
- package/dist/state-C7gCoiHr.mjs +153 -0
- package/dist/state-C7gCoiHr.mjs.map +1 -0
- package/dist/status-DLoBmcDz.mjs +30 -0
- package/dist/status-DLoBmcDz.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/storage-query-CPctdMKX.d.mts +1519 -0
- package/dist/storage-query-CPctdMKX.d.mts.map +1 -0
- package/dist/target-CUKlGrXb.mjs +27 -0
- package/dist/target-CUKlGrXb.mjs.map +1 -0
- package/dist/taxonomies-BpqpXJUE.mjs +707 -0
- package/dist/taxonomies-BpqpXJUE.mjs.map +1 -0
- package/dist/taxonomies-ClCo4IGO.mjs +899 -0
- package/dist/taxonomies-ClCo4IGO.mjs.map +1 -0
- package/dist/taxonomy-Dj1vpw5E.mjs +508 -0
- package/dist/taxonomy-Dj1vpw5E.mjs.map +1 -0
- package/dist/tokens-Ns02GAma.mjs +171 -0
- package/dist/tokens-Ns02GAma.mjs.map +1 -0
- package/dist/transaction-BcJO4Tmc.mjs +29 -0
- package/dist/transaction-BcJO4Tmc.mjs.map +1 -0
- package/dist/transport-B8P1xsqk.mjs +136 -0
- package/dist/transport-B8P1xsqk.mjs.map +1 -0
- package/dist/transport-BLHZZcD_.d.mts +42 -0
- package/dist/transport-BLHZZcD_.d.mts.map +1 -0
- package/dist/trusted-proxy-Cg7SuD15.mjs +51 -0
- package/dist/trusted-proxy-Cg7SuD15.mjs.map +1 -0
- package/dist/turnstile-DWCSh_Qc.mjs +53 -0
- package/dist/turnstile-DWCSh_Qc.mjs.map +1 -0
- package/dist/types-B3RkqvDW.mjs +156 -0
- package/dist/types-B3RkqvDW.mjs.map +1 -0
- package/dist/types-BkUg2yHx.mjs +92 -0
- package/dist/types-BkUg2yHx.mjs.map +1 -0
- package/dist/types-BtuppOTV.mjs +16 -0
- package/dist/types-BtuppOTV.mjs.map +1 -0
- package/dist/types-CCR3ivXE.d.mts +363 -0
- package/dist/types-CCR3ivXE.d.mts.map +1 -0
- package/dist/types-CSHgU_-_.mjs +18 -0
- package/dist/types-CSHgU_-_.mjs.map +1 -0
- package/dist/types-CbwqGOXm.d.mts +766 -0
- package/dist/types-CbwqGOXm.d.mts.map +1 -0
- package/dist/types-D4RGIc2I.d.mts +198 -0
- package/dist/types-D4RGIc2I.d.mts.map +1 -0
- package/dist/types-DEHidMEk.d.mts +1637 -0
- package/dist/types-DEHidMEk.d.mts.map +1 -0
- package/dist/types-DQeU2SR7.d.mts +279 -0
- package/dist/types-DQeU2SR7.d.mts.map +1 -0
- package/dist/types-DxQWoQLA.d.mts +264 -0
- package/dist/types-DxQWoQLA.d.mts.map +1 -0
- package/dist/types-FBBnGZ2Y.d.mts +198 -0
- package/dist/types-FBBnGZ2Y.d.mts.map +1 -0
- package/dist/types-ZCnlropY.mjs +69 -0
- package/dist/types-ZCnlropY.mjs.map +1 -0
- package/dist/types-_Qtyawiy.d.mts +124 -0
- package/dist/types-_Qtyawiy.d.mts.map +1 -0
- package/dist/types-gC6FAoa_.d.mts +75 -0
- package/dist/types-gC6FAoa_.d.mts.map +1 -0
- package/dist/types-k--LneIF.mjs +22 -0
- package/dist/types-k--LneIF.mjs.map +1 -0
- package/dist/upload-attempts-2xdnoKGe.mjs +27 -0
- package/dist/upload-attempts-2xdnoKGe.mjs.map +1 -0
- package/dist/url-pattern-3m3reMzr.mjs +33 -0
- package/dist/url-pattern-3m3reMzr.mjs.map +1 -0
- package/dist/user-DroRntkx.mjs +171 -0
- package/dist/user-DroRntkx.mjs.map +1 -0
- package/dist/utils-CC2oNGV8.mjs +435 -0
- package/dist/utils-CC2oNGV8.mjs.map +1 -0
- package/dist/validate-BCP9HNDn.mjs +384 -0
- package/dist/validate-BCP9HNDn.mjs.map +1 -0
- package/dist/validate-CyQ7I3xF.d.mts +410 -0
- package/dist/validate-CyQ7I3xF.d.mts.map +1 -0
- package/dist/validate-DANX1-Qi.mjs +120 -0
- package/dist/validate-DANX1-Qi.mjs.map +1 -0
- package/dist/validation-DBy6WF94.mjs +216 -0
- package/dist/validation-DBy6WF94.mjs.map +1 -0
- package/dist/version-B57E4Uo7.mjs +7 -0
- package/dist/version-B57E4Uo7.mjs.map +1 -0
- package/dist/widgets-wQ7Xcgq8.mjs +126 -0
- package/dist/widgets-wQ7Xcgq8.mjs.map +1 -0
- package/dist/wxr-taxonomies-DIHfvEDt.mjs +406 -0
- package/dist/wxr-taxonomies-DIHfvEDt.mjs.map +1 -0
- package/dist/wxr-taxonomies-DU2ZSiGc.d.mts +34 -0
- package/dist/wxr-taxonomies-DU2ZSiGc.d.mts.map +1 -0
- package/dist/zod-generator-D_yHIWfs.mjs +329 -0
- package/dist/zod-generator-D_yHIWfs.mjs.map +1 -0
- package/package.json +39 -12
- package/src/api/errors.ts +23 -0
- package/src/api/handlers/backup.ts +11 -5
- package/src/api/handlers/content.ts +226 -85
- package/src/api/handlers/dashboard.ts +31 -1
- package/src/api/handlers/entry-lock.ts +206 -0
- package/src/api/handlers/index.ts +3 -0
- package/src/api/handlers/manifest.ts +5 -6
- package/src/api/handlers/marketplace.ts +126 -34
- package/src/api/handlers/media-upload.ts +31 -4
- package/src/api/handlers/menus.ts +9 -0
- package/src/api/handlers/plugin-settings.ts +35 -3
- package/src/api/handlers/redirects.ts +221 -138
- package/src/api/handlers/registry.ts +75 -29
- package/src/api/handlers/revision.ts +16 -27
- package/src/api/handlers/seo.ts +10 -1
- package/src/api/handlers/snapshot.ts +87 -72
- package/src/api/handlers/taxonomies.ts +79 -5
- package/src/api/handlers/validation.ts +120 -19
- package/src/api/openapi/document.ts +133 -11
- package/src/api/schemas/content.ts +32 -12
- package/src/api/schemas/entry-lock.ts +57 -0
- package/src/api/schemas/index.ts +1 -0
- package/src/api/schemas/schema.ts +10 -1
- package/src/api/schemas/search.ts +4 -0
- package/src/api/types.ts +4 -0
- package/src/astro/integration/index.ts +22 -6
- package/src/astro/integration/routes.ts +89 -0
- package/src/astro/integration/runtime.ts +40 -24
- package/src/astro/integration/virtual-modules.ts +4 -0
- package/src/astro/integration/vite-config.ts +31 -0
- package/src/astro/middleware/auth.ts +25 -4
- package/src/astro/middleware/request-context.ts +28 -10
- package/src/astro/middleware.ts +33 -1
- package/src/astro/prefetch.ts +2 -2
- package/src/astro/routes/api/admin/comments/[id]/status.ts +22 -58
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +2 -15
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +2 -25
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +1 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +23 -4
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +12 -2
- package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +1 -0
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +29 -10
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +8 -2
- package/src/astro/routes/api/admin/plugins/registry/install.ts +15 -4
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +2 -1
- package/src/astro/routes/api/admin/plugins/updates.ts +6 -1
- package/src/astro/routes/api/admin/scheduled-policy-rejections/[collection]/[id].ts +34 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +4 -259
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +10 -0
- package/src/astro/routes/api/content/[collection]/[id]/lock.ts +133 -0
- package/src/astro/routes/api/content/[collection]/[id]/plugin-extensions/[pluginId]/[kind]/[extensionId].ts +29 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +21 -4
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +30 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +15 -1
- package/src/astro/routes/api/content/[collection]/[id].ts +27 -2
- package/src/astro/routes/api/content/[collection]/index.ts +3 -0
- package/src/astro/routes/api/health.ts +23 -0
- package/src/astro/routes/api/manifest.ts +14 -4
- package/src/astro/routes/api/mcp.ts +2 -1
- package/src/astro/routes/api/media/asset/[id]/[filename].ts +50 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +13 -81
- package/src/astro/routes/api/redirects/[id].ts +0 -3
- package/src/astro/routes/api/redirects/index.ts +0 -2
- package/src/astro/routes/api/search/index.ts +1 -0
- package/src/astro/routes/api/visual-editing/action-token.ts +36 -0
- package/src/astro/routes/api/visual-editing/content/[collection]/[id]/publish.ts +32 -0
- package/src/astro/routes/api/visual-editing/toolbar-labels.ts +16 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +11 -4
- package/src/astro/types.ts +83 -12
- package/src/cli/commands/bundle-utils.ts +19 -19
- package/src/cli/commands/bundle.ts +9 -6
- package/src/cli/commands/content.ts +32 -6
- package/src/cli/commands/doctor.ts +25 -0
- package/src/cli/commands/export-seed.ts +195 -56
- package/src/cli/commands/migrate.ts +71 -23
- package/src/cli/commands/publish.ts +2 -2
- package/src/client/index.ts +34 -7
- package/src/comments/public-submission.ts +246 -0
- package/src/comments/service.ts +59 -12
- package/src/components/EmDashBodyEnd.astro +4 -1
- package/src/components/EmDashBodyStart.astro +4 -1
- package/src/components/EmDashHead.astro +36 -16
- package/src/components/Gallery.astro +18 -4
- package/src/components/InlineEditor.astro +3 -1
- package/src/components/InlinePortableTextEditor.tsx +106 -11
- package/src/components/PortableText.astro +4 -0
- package/src/components/Table.astro +147 -62
- package/src/components/widgets/Archives.astro +6 -5
- package/src/config/errors.ts +13 -0
- package/src/config/secrets.ts +25 -11
- package/src/content/converters/portable-text-to-prosemirror.ts +26 -2
- package/src/content/converters/prosemirror-to-portable-text.ts +35 -6
- package/src/content/converters/types.ts +10 -0
- package/src/content/known-fields.ts +44 -0
- package/src/database/connection.ts +5 -1
- package/src/database/content-datetime.ts +123 -0
- package/src/database/datetime-storage.ts +452 -0
- package/src/database/dialect-helpers.ts +161 -1
- package/src/database/migration-lock.ts +140 -0
- package/src/database/migrations/075_entry_edit_locks.ts +44 -0
- package/src/database/migrations/076_collection_nav_group.ts +22 -0
- package/src/database/migrations/077_plugin_storage_revisions.ts +89 -0
- package/src/database/migrations/078_menu_item_translation_groups.ts +15 -0
- package/src/database/migrations/079_datetime_normalization.ts +13 -0
- package/src/database/migrations/080_content_translation_locale_unique.ts +88 -0
- package/src/database/migrations/081_redirect_write_guards.ts +257 -0
- package/src/database/migrations/082_taxonomy_translation_locale_unique.ts +49 -0
- package/src/database/migrations/runner.ts +63 -15
- package/src/database/pg-migration-lock.ts +2 -2
- package/src/database/repositories/byline.ts +9 -0
- package/src/database/repositories/comment.ts +86 -0
- package/src/database/repositories/content.ts +560 -69
- package/src/database/repositories/entry-locks.ts +257 -0
- package/src/database/repositories/media.ts +35 -4
- package/src/database/repositories/menu.ts +1 -0
- package/src/database/repositories/options.ts +113 -7
- package/src/database/repositories/plugin-storage.ts +159 -0
- package/src/database/repositories/redirect.ts +262 -56
- package/src/database/repositories/revision.ts +116 -17
- package/src/database/repositories/taxonomy.ts +42 -0
- package/src/database/repositories/types.ts +5 -0
- package/src/database/types.ts +26 -1
- package/src/datetime-normalization.ts +311 -0
- package/src/db/node-sqlite-compat.ts +3 -2
- package/src/emdash-runtime.ts +1994 -424
- package/src/fields/image.ts +2 -0
- package/src/i18n/config.ts +6 -6
- package/src/i18n/resolve.ts +98 -15
- package/src/index.ts +101 -0
- package/src/loader.ts +49 -4
- package/src/mcp/server.ts +216 -68
- package/src/media/responsive.ts +23 -0
- package/src/media/usage/content-refresh.ts +2 -1
- package/src/media/usage/extractor.ts +50 -15
- package/src/media/usage/types.ts +1 -1
- package/src/menus/index.ts +64 -35
- package/src/migrations/direct-executor.ts +40 -2
- package/src/migrations/index.ts +1 -0
- package/src/migrations/protocol.ts +11 -1
- package/src/page/seo-contributions.ts +78 -1
- package/src/page/seo-panel.ts +47 -0
- package/src/plugin-test-runtime.ts +17 -0
- package/src/plugin-types.ts +128 -21
- package/src/plugins/adapt-sandbox-entry.ts +34 -27
- package/src/plugins/conditional-storage.ts +30 -0
- package/src/plugins/content-access.ts +170 -0
- package/src/plugins/content-policy.ts +74 -0
- package/src/plugins/context.ts +790 -166
- package/src/plugins/cron.ts +18 -10
- package/src/plugins/define-plugin.ts +55 -54
- package/src/plugins/editor-draft.ts +257 -0
- package/src/plugins/hooks.ts +136 -3
- package/src/plugins/host.ts +29 -0
- package/src/plugins/http-route-dispatch.ts +389 -0
- package/src/plugins/http-wire.ts +180 -0
- package/src/plugins/index.ts +97 -3
- package/src/plugins/install-finalization.ts +77 -0
- package/src/plugins/lifecycle.ts +47 -0
- package/src/plugins/manager.ts +5 -2
- package/src/plugins/manifest-schema.ts +314 -58
- package/src/plugins/media.ts +166 -0
- package/src/plugins/request-meta.ts +12 -2
- package/src/plugins/route-wire.ts +304 -0
- package/src/plugins/routes.ts +38 -5
- package/src/plugins/sandbox/index.ts +4 -0
- package/src/plugins/sandbox/proxy.ts +129 -0
- package/src/plugins/sandbox/types.ts +83 -7
- package/src/plugins/secret-redactor.ts +65 -0
- package/src/plugins/settings.ts +303 -0
- package/src/plugins/state.ts +26 -0
- package/src/plugins/storage-query.ts +45 -0
- package/src/plugins/storage-update.ts +96 -0
- package/src/plugins/types.ts +602 -15
- package/src/query.ts +84 -4
- package/src/registry/authoritative-records.ts +26 -0
- package/src/registry/config.ts +182 -31
- package/src/registry/testing.ts +100 -0
- package/src/registry/types.ts +12 -70
- package/src/scheduled-publish.ts +70 -3
- package/src/schema/collection-slugs-cache.ts +157 -0
- package/src/schema/index.ts +1 -0
- package/src/schema/registry.ts +64 -1
- package/src/schema/types.ts +32 -6
- package/src/schema/zod-generator.ts +5 -13
- package/src/search/fts-manager.ts +3 -3
- package/src/search/query.ts +32 -5
- package/src/search/types.ts +8 -0
- package/src/security/ssrf.ts +167 -141
- package/src/seed/apply.ts +41 -3
- package/src/seed/types.ts +13 -3
- package/src/seed/validate.ts +18 -1
- package/src/seo/hreflang.ts +10 -6
- package/src/seo/index.ts +5 -10
- package/src/seo/media-url.ts +26 -0
- package/src/settings/index.ts +53 -11
- package/src/taxonomies/term-counts.ts +22 -5
- package/src/visual-editing/action-token.ts +31 -0
- package/src/visual-editing/toolbar-bootstrap.ts +31 -6
- package/src/visual-editing/toolbar.ts +103 -12
- package/src/widgets/archives.ts +10 -9
- package/src/widgets/index.ts +11 -1
- package/dist/activation-K0kGBWuJ.mjs +0 -382
- package/dist/activation-K0kGBWuJ.mjs.map +0 -1
- package/dist/adapters-BDQwg236.d.mts +0 -171
- package/dist/adapters-BDQwg236.d.mts.map +0 -1
- package/dist/after-CBU2vkoO.mjs +0 -96
- package/dist/after-CBU2vkoO.mjs.map +0 -1
- package/dist/allowed-origins-BGglilcs.mjs +0 -116
- package/dist/allowed-origins-BGglilcs.mjs.map +0 -1
- package/dist/api-Dz6rgoa3.mjs +0 -10040
- package/dist/api-Dz6rgoa3.mjs.map +0 -1
- package/dist/api-tokens-BSsQACNe.mjs +0 -163
- package/dist/api-tokens-BSsQACNe.mjs.map +0 -1
- package/dist/apply-B4SIOxR1.mjs +0 -980
- package/dist/apply-B4SIOxR1.mjs.map +0 -1
- package/dist/authorize-Bkf_UHhD.mjs +0 -40
- package/dist/authorize-Bkf_UHhD.mjs.map +0 -1
- package/dist/backup-rwVAl9NI.mjs +0 -241
- package/dist/backup-rwVAl9NI.mjs.map +0 -1
- package/dist/base64-CvLhUKQv.mjs +0 -63
- package/dist/base64-CvLhUKQv.mjs.map +0 -1
- package/dist/bundle-C8S2Zl6U.mjs +0 -663
- package/dist/bundle-C8S2Zl6U.mjs.map +0 -1
- package/dist/byline-DuhF7NWl.mjs +0 -902
- package/dist/byline-DuhF7NWl.mjs.map +0 -1
- package/dist/byline-fields-BovY4KYM.mjs +0 -123
- package/dist/byline-fields-BovY4KYM.mjs.map +0 -1
- package/dist/byline-registry-Bpu9-MVs.mjs +0 -406
- package/dist/byline-registry-Bpu9-MVs.mjs.map +0 -1
- package/dist/bylines-CJ5nd6Lw.mjs +0 -232
- package/dist/bylines-CJ5nd6Lw.mjs.map +0 -1
- package/dist/bylines-RwBAeOF1.mjs +0 -214
- package/dist/bylines-RwBAeOF1.mjs.map +0 -1
- package/dist/cache-BF5Kvn59.mjs +0 -108
- package/dist/cache-BF5Kvn59.mjs.map +0 -1
- package/dist/capture-triggers-CNW1q3HK.mjs +0 -362
- package/dist/capture-triggers-CNW1q3HK.mjs.map +0 -1
- package/dist/challenge-store-DQN_Yrck.mjs +0 -51
- package/dist/challenge-store-DQN_Yrck.mjs.map +0 -1
- package/dist/chrome-tags-D8fiZG94.mjs +0 -24
- package/dist/chrome-tags-D8fiZG94.mjs.map +0 -1
- package/dist/chunks-C4szrD8o.mjs +0 -25
- package/dist/chunks-C4szrD8o.mjs.map +0 -1
- package/dist/collection-deletion-Bj07NHbj.mjs +0 -436
- package/dist/collection-deletion-Bj07NHbj.mjs.map +0 -1
- package/dist/comment-reaction-BhrvSHml.mjs +0 -85
- package/dist/comment-reaction-BhrvSHml.mjs.map +0 -1
- package/dist/comment-vxOzWbZN.mjs +0 -255
- package/dist/comment-vxOzWbZN.mjs.map +0 -1
- package/dist/comments-Ct4ensnf.mjs +0 -204
- package/dist/comments-Ct4ensnf.mjs.map +0 -1
- package/dist/components-DJbo1z0S.mjs +0 -108
- package/dist/components-DJbo1z0S.mjs.map +0 -1
- package/dist/config-B9eZ340f.d.mts +0 -34
- package/dist/config-B9eZ340f.d.mts.map +0 -1
- package/dist/config-C3EBstHi.mjs +0 -72
- package/dist/config-C3EBstHi.mjs.map +0 -1
- package/dist/config-it29yDLA.mjs +0 -1163
- package/dist/config-it29yDLA.mjs.map +0 -1
- package/dist/content-DjvM0T92.mjs +0 -1725
- package/dist/content-DjvM0T92.mjs.map +0 -1
- package/dist/content-list-query-Btqd4uV2.d.mts +0 -26
- package/dist/content-list-query-Btqd4uV2.d.mts.map +0 -1
- package/dist/content-refresh-Bwp-8yGy.mjs +0 -3588
- package/dist/content-refresh-Bwp-8yGy.mjs.map +0 -1
- package/dist/content-repair-Czdp7jz5.mjs +0 -440
- package/dist/content-repair-Czdp7jz5.mjs.map +0 -1
- package/dist/context-CX6gxOLW.mjs +0 -1068
- package/dist/context-CX6gxOLW.mjs.map +0 -1
- package/dist/cron-C6o7VppJ.mjs +0 -277
- package/dist/cron-C6o7VppJ.mjs.map +0 -1
- package/dist/dashboard-C2kTeeRI.mjs +0 -140
- package/dist/dashboard-C2kTeeRI.mjs.map +0 -1
- package/dist/db-errors-Cl-sKYTm.mjs +0 -55
- package/dist/db-errors-Cl-sKYTm.mjs.map +0 -1
- package/dist/default-Clra32mw.mjs +0 -81
- package/dist/default-Clra32mw.mjs.map +0 -1
- package/dist/deferred-tasks-CvDETTJO.d.mts +0 -9
- package/dist/deferred-tasks-CvDETTJO.d.mts.map +0 -1
- package/dist/dev-typegen-DzOPfsNj.mjs +0 -29
- package/dist/dev-typegen-DzOPfsNj.mjs.map +0 -1
- package/dist/device-flow-D2oCWvLJ.mjs +0 -466
- package/dist/device-flow-D2oCWvLJ.mjs.map +0 -1
- package/dist/dialect-helpers-BSbfaO3F.mjs +0 -202
- package/dist/dialect-helpers-BSbfaO3F.mjs.map +0 -1
- package/dist/direct-executor-Bfa5_ToE.mjs +0 -85
- package/dist/direct-executor-Bfa5_ToE.mjs.map +0 -1
- package/dist/dist-89xCrGqi.mjs +0 -810
- package/dist/dist-89xCrGqi.mjs.map +0 -1
- package/dist/email-console-Dzb6uGYa.mjs +0 -50
- package/dist/email-console-Dzb6uGYa.mjs.map +0 -1
- package/dist/enrich-BX0IDp4z.mjs +0 -194
- package/dist/enrich-BX0IDp4z.mjs.map +0 -1
- package/dist/error-DFrQjppn.mjs +0 -90
- package/dist/error-DFrQjppn.mjs.map +0 -1
- package/dist/errors-DsVoDUjJ.mjs +0 -427
- package/dist/errors-DsVoDUjJ.mjs.map +0 -1
- package/dist/escape-HmHTC1Is.mjs +0 -9
- package/dist/escape-HmHTC1Is.mjs.map +0 -1
- package/dist/field-defs-cache-BM4SIRqH.mjs +0 -77
- package/dist/field-defs-cache-BM4SIRqH.mjs.map +0 -1
- package/dist/focal-point-BeWFo6Xx.mjs +0 -23
- package/dist/focal-point-BeWFo6Xx.mjs.map +0 -1
- package/dist/fts-manager-Do1BlW2r.mjs +0 -413
- package/dist/fts-manager-Do1BlW2r.mjs.map +0 -1
- package/dist/hash-3JJPlHF2.mjs +0 -37
- package/dist/hash-3JJPlHF2.mjs.map +0 -1
- package/dist/hook-result-DCh2WUpe.d.mts +0 -31
- package/dist/hook-result-DCh2WUpe.d.mts.map +0 -1
- package/dist/hreflang-B6hbAuuO.d.mts +0 -48
- package/dist/hreflang-B6hbAuuO.d.mts.map +0 -1
- package/dist/hreflang-DQbPZliA.mjs +0 -102
- package/dist/hreflang-DQbPZliA.mjs.map +0 -1
- package/dist/identity-DksvEazf.mjs +0 -35
- package/dist/identity-DksvEazf.mjs.map +0 -1
- package/dist/import-CJpaBBBT.mjs +0 -2020
- package/dist/import-CJpaBBBT.mjs.map +0 -1
- package/dist/index-BJNMCWmu.d.mts +0 -6562
- package/dist/index-BJNMCWmu.d.mts.map +0 -1
- package/dist/index-Du8K7bWa.d.mts +0 -278
- package/dist/index-Du8K7bWa.d.mts.map +0 -1
- package/dist/init-lock-DJkX6Hto.mjs +0 -56
- package/dist/init-lock-DJkX6Hto.mjs.map +0 -1
- package/dist/load-CawHjTOH.mjs +0 -28
- package/dist/load-CawHjTOH.mjs.map +0 -1
- package/dist/loader-Z8vl7zTq.mjs +0 -966
- package/dist/loader-Z8vl7zTq.mjs.map +0 -1
- package/dist/manifest-builder-COtzuca2.mjs +0 -189
- package/dist/manifest-builder-COtzuca2.mjs.map +0 -1
- package/dist/manifest-schema-BNWwR8Vd.mjs +0 -301
- package/dist/manifest-schema-BNWwR8Vd.mjs.map +0 -1
- package/dist/media-BBm8Wg3f.mjs +0 -318
- package/dist/media-BBm8Wg3f.mjs.map +0 -1
- package/dist/media-BHjus86Y.mjs +0 -464
- package/dist/media-BHjus86Y.mjs.map +0 -1
- package/dist/media-allowlist-CoTBWoDp.mjs +0 -44
- package/dist/media-allowlist-CoTBWoDp.mjs.map +0 -1
- package/dist/media-folders-BGkATs8n.mjs +0 -210
- package/dist/media-folders-BGkATs8n.mjs.map +0 -1
- package/dist/media-upload-BCidR-EY.mjs +0 -147
- package/dist/media-upload-BCidR-EY.mjs.map +0 -1
- package/dist/media-url-DHoPr0hq.mjs +0 -26
- package/dist/media-url-DHoPr0hq.mjs.map +0 -1
- package/dist/media-usage-CdY5jhSR.mjs +0 -1833
- package/dist/media-usage-CdY5jhSR.mjs.map +0 -1
- package/dist/media-usage-activation-BgeMtK5C.mjs +0 -78
- package/dist/media-usage-activation-BgeMtK5C.mjs.map +0 -1
- package/dist/media-usage-work-CnGCdHxx.mjs +0 -152
- package/dist/media-usage-work-CnGCdHxx.mjs.map +0 -1
- package/dist/media-usage-work-D6D9sMCA.mjs +0 -586
- package/dist/media-usage-work-D6D9sMCA.mjs.map +0 -1
- package/dist/media-usage-write-fence-hjeD4u7s.mjs +0 -42
- package/dist/media-usage-write-fence-hjeD4u7s.mjs.map +0 -1
- package/dist/menus-6qSwTNxG.mjs +0 -4010
- package/dist/menus-6qSwTNxG.mjs.map +0 -1
- package/dist/menus-uvPLXMZf.mjs +0 -744
- package/dist/menus-uvPLXMZf.mjs.map +0 -1
- package/dist/mime-CUIG6x84.mjs +0 -36
- package/dist/mime-CUIG6x84.mjs.map +0 -1
- package/dist/mode-DN_WneRx.mjs +0 -23
- package/dist/mode-DN_WneRx.mjs.map +0 -1
- package/dist/node-sqlite-compat-BuJXIeMz.mjs +0 -46
- package/dist/node-sqlite-compat-BuJXIeMz.mjs.map +0 -1
- package/dist/normalize-C2xNjTSG.mjs +0 -191
- package/dist/normalize-C2xNjTSG.mjs.map +0 -1
- package/dist/oauth-authorization-Dj6Kwc21.mjs +0 -274
- package/dist/oauth-authorization-Dj6Kwc21.mjs.map +0 -1
- package/dist/oauth-clients-FD7I0J8m.mjs +0 -266
- package/dist/oauth-clients-FD7I0J8m.mjs.map +0 -1
- package/dist/oauth-state-store-DkmDOmHs.mjs +0 -50
- package/dist/oauth-state-store-DkmDOmHs.mjs.map +0 -1
- package/dist/oauth-user-lookup-CvIwGpYd.mjs +0 -26
- package/dist/oauth-user-lookup-CvIwGpYd.mjs.map +0 -1
- package/dist/object-cache-DVKnyOfy.mjs +0 -534
- package/dist/object-cache-DVKnyOfy.mjs.map +0 -1
- package/dist/options-BHPeIbBd.mjs +0 -117
- package/dist/options-BHPeIbBd.mjs.map +0 -1
- package/dist/options-CYb4y7hM.d.mts +0 -221
- package/dist/options-CYb4y7hM.d.mts.map +0 -1
- package/dist/parse-Ckpg-Qfp.mjs +0 -81
- package/dist/parse-Ckpg-Qfp.mjs.map +0 -1
- package/dist/passkey-config-O_lj3y0k.mjs +0 -46
- package/dist/passkey-config-O_lj3y0k.mjs.map +0 -1
- package/dist/patterns-D9iDO3j8.mjs +0 -145
- package/dist/patterns-D9iDO3j8.mjs.map +0 -1
- package/dist/placeholder-4X9BrRrp.d.mts +0 -306
- package/dist/placeholder-4X9BrRrp.d.mts.map +0 -1
- package/dist/policy-Dhtwntrt.mjs +0 -45
- package/dist/policy-Dhtwntrt.mjs.map +0 -1
- package/dist/portable-text-U85hOafW.mjs +0 -286
- package/dist/portable-text-U85hOafW.mjs.map +0 -1
- package/dist/preview-B_vJLvf8.mjs +0 -107
- package/dist/preview-B_vJLvf8.mjs.map +0 -1
- package/dist/protocol-JdD2YhY9.d.mts +0 -52
- package/dist/protocol-JdD2YhY9.d.mts.map +0 -1
- package/dist/public-url-CarhZJgf.mjs +0 -101
- package/dist/public-url-CarhZJgf.mjs.map +0 -1
- package/dist/query-BZKZcG5b.mjs +0 -881
- package/dist/query-BZKZcG5b.mjs.map +0 -1
- package/dist/query-BndaFxxp.mjs +0 -41
- package/dist/query-BndaFxxp.mjs.map +0 -1
- package/dist/rate-limit-BZmATC6W.mjs +0 -120
- package/dist/rate-limit-BZmATC6W.mjs.map +0 -1
- package/dist/redirect-CZkbozu9.mjs +0 -313
- package/dist/redirect-CZkbozu9.mjs.map +0 -1
- package/dist/redirect-CzqnLxK-.mjs +0 -17
- package/dist/redirect-CzqnLxK-.mjs.map +0 -1
- package/dist/redirects-BLNOWQTn.mjs +0 -1238
- package/dist/redirects-BLNOWQTn.mjs.map +0 -1
- package/dist/redirects-CqzNM0KM.mjs +0 -579
- package/dist/redirects-CqzNM0KM.mjs.map +0 -1
- package/dist/registry-AZAsRsor.mjs +0 -1179
- package/dist/registry-AZAsRsor.mjs.map +0 -1
- package/dist/relation-04DfKRTO.mjs +0 -334
- package/dist/relation-04DfKRTO.mjs.map +0 -1
- package/dist/relations-C4htk5sb.mjs +0 -309
- package/dist/relations-C4htk5sb.mjs.map +0 -1
- package/dist/relations-CcFwDJdJ.mjs +0 -403
- package/dist/relations-CcFwDJdJ.mjs.map +0 -1
- package/dist/relations-DnRK4YIT.d.mts +0 -3354
- package/dist/relations-DnRK4YIT.d.mts.map +0 -1
- package/dist/request-cache-DH9zdCOD.mjs +0 -104
- package/dist/request-cache-DH9zdCOD.mjs.map +0 -1
- package/dist/request-meta-DYxLlnmz.mjs +0 -140
- package/dist/request-meta-DYxLlnmz.mjs.map +0 -1
- package/dist/resolve-prZ3mP7l.mjs +0 -143
- package/dist/resolve-prZ3mP7l.mjs.map +0 -1
- package/dist/runner-BLIDKpmA.mjs +0 -4676
- package/dist/runner-BLIDKpmA.mjs.map +0 -1
- package/dist/runner-YKfIMnaF.d.mts +0 -67
- package/dist/runner-YKfIMnaF.d.mts.map +0 -1
- package/dist/schema-CGnBeLiW.mjs +0 -9
- package/dist/schema-CGnBeLiW.mjs.map +0 -1
- package/dist/schema-DYr-Vd-L.mjs +0 -420
- package/dist/schema-DYr-Vd-L.mjs.map +0 -1
- package/dist/scopes-BhWvBavj.mjs +0 -27
- package/dist/scopes-BhWvBavj.mjs.map +0 -1
- package/dist/search-C-qDk4kx.mjs +0 -439
- package/dist/search-C-qDk4kx.mjs.map +0 -1
- package/dist/secrets-rEtHt-6z.mjs +0 -330
- package/dist/secrets-rEtHt-6z.mjs.map +0 -1
- package/dist/sections-B_nYvlwn.mjs +0 -346
- package/dist/sections-B_nYvlwn.mjs.map +0 -1
- package/dist/seo-926NRIgt.mjs +0 -133
- package/dist/seo-926NRIgt.mjs.map +0 -1
- package/dist/seo-CVWkdv6x.mjs +0 -113
- package/dist/seo-CVWkdv6x.mjs.map +0 -1
- package/dist/service-CJl3ZAYs.mjs +0 -195
- package/dist/service-CJl3ZAYs.mjs.map +0 -1
- package/dist/session-user-BlMgqCHS.mjs +0 -51
- package/dist/session-user-BlMgqCHS.mjs.map +0 -1
- package/dist/settings--wobrkkC.mjs +0 -258
- package/dist/settings--wobrkkC.mjs.map +0 -1
- package/dist/settings-Cwm6o2jY.mjs +0 -51
- package/dist/settings-Cwm6o2jY.mjs.map +0 -1
- package/dist/setup-complete-DQbClIN2.mjs +0 -26
- package/dist/setup-complete-DQbClIN2.mjs.map +0 -1
- package/dist/setup-nonce-DZCFS2sn.mjs +0 -25
- package/dist/setup-nonce-DZCFS2sn.mjs.map +0 -1
- package/dist/single-flight-cache-BPuGPdcN.mjs +0 -104
- package/dist/single-flight-cache-BPuGPdcN.mjs.map +0 -1
- package/dist/site-url-BrxA_E9H.mjs +0 -16
- package/dist/site-url-BrxA_E9H.mjs.map +0 -1
- package/dist/slugify-B994zkXC.mjs +0 -17
- package/dist/slugify-B994zkXC.mjs.map +0 -1
- package/dist/snapshot--OCDTqdb.mjs +0 -216
- package/dist/snapshot--OCDTqdb.mjs.map +0 -1
- package/dist/ssrf-5sIM5jzl.mjs +0 -349
- package/dist/ssrf-5sIM5jzl.mjs.map +0 -1
- package/dist/state-BpFVsJZB.mjs +0 -136
- package/dist/state-BpFVsJZB.mjs.map +0 -1
- package/dist/status-B777-dXz.mjs +0 -30
- package/dist/status-B777-dXz.mjs.map +0 -1
- package/dist/target-BmR0iTwz.mjs +0 -27
- package/dist/target-BmR0iTwz.mjs.map +0 -1
- package/dist/taxonomies-DkAkMupr.mjs +0 -837
- package/dist/taxonomies-DkAkMupr.mjs.map +0 -1
- package/dist/taxonomies-Wfy_Lg12.mjs +0 -698
- package/dist/taxonomies-Wfy_Lg12.mjs.map +0 -1
- package/dist/taxonomy-tJepplLL.mjs +0 -484
- package/dist/taxonomy-tJepplLL.mjs.map +0 -1
- package/dist/tokens-BCO1oruF.mjs +0 -171
- package/dist/tokens-BCO1oruF.mjs.map +0 -1
- package/dist/transaction-0KOpOyMu.mjs +0 -29
- package/dist/transaction-0KOpOyMu.mjs.map +0 -1
- package/dist/transport-Dr3qtwXC.mjs +0 -136
- package/dist/transport-Dr3qtwXC.mjs.map +0 -1
- package/dist/transport-xh6YKW2G.d.mts +0 -42
- package/dist/transport-xh6YKW2G.d.mts.map +0 -1
- package/dist/trusted-proxy-BR5F1Otp.mjs +0 -51
- package/dist/trusted-proxy-BR5F1Otp.mjs.map +0 -1
- package/dist/types-3qNFPlci.mjs +0 -16
- package/dist/types-3qNFPlci.mjs.map +0 -1
- package/dist/types-75KIqzL9.mjs +0 -142
- package/dist/types-75KIqzL9.mjs.map +0 -1
- package/dist/types-B6GrPic4.d.mts +0 -1335
- package/dist/types-B6GrPic4.d.mts.map +0 -1
- package/dist/types-BuHW4xDE.d.mts +0 -259
- package/dist/types-BuHW4xDE.d.mts.map +0 -1
- package/dist/types-C00oyCZp.d.mts +0 -198
- package/dist/types-C00oyCZp.d.mts.map +0 -1
- package/dist/types-CDtkNSFQ.d.mts +0 -75
- package/dist/types-CDtkNSFQ.d.mts.map +0 -1
- package/dist/types-CPeXo1wF.d.mts +0 -124
- package/dist/types-CPeXo1wF.d.mts.map +0 -1
- package/dist/types-CQPWhPxE.mjs +0 -92
- package/dist/types-CQPWhPxE.mjs.map +0 -1
- package/dist/types-CXFkwEGC.d.mts +0 -198
- package/dist/types-CXFkwEGC.d.mts.map +0 -1
- package/dist/types-DM3vioBY.mjs +0 -18
- package/dist/types-DM3vioBY.mjs.map +0 -1
- package/dist/types-DczELMop.d.mts +0 -363
- package/dist/types-DczELMop.d.mts.map +0 -1
- package/dist/types-DfuTR6dL.mjs +0 -3
- package/dist/types-FV23hEoW.d.mts +0 -743
- package/dist/types-FV23hEoW.d.mts.map +0 -1
- package/dist/types-xDMtUFnO.d.mts +0 -257
- package/dist/types-xDMtUFnO.d.mts.map +0 -1
- package/dist/upload-attempts-BsqoQ1fn.mjs +0 -27
- package/dist/upload-attempts-BsqoQ1fn.mjs.map +0 -1
- package/dist/url-pattern-D4c2czpJ.mjs +0 -33
- package/dist/url-pattern-D4c2czpJ.mjs.map +0 -1
- package/dist/user-BTZ40aq6.mjs +0 -171
- package/dist/user-BTZ40aq6.mjs.map +0 -1
- package/dist/utils-BKvNjjhY.mjs +0 -435
- package/dist/utils-BKvNjjhY.mjs.map +0 -1
- package/dist/validate-BpwoDOgt.mjs +0 -120
- package/dist/validate-BpwoDOgt.mjs.map +0 -1
- package/dist/validate-DE_LRwo9.mjs +0 -379
- package/dist/validate-DE_LRwo9.mjs.map +0 -1
- package/dist/validate-DUP27OYD.d.mts +0 -400
- package/dist/validate-DUP27OYD.d.mts.map +0 -1
- package/dist/validation-BMImFJ11.mjs +0 -153
- package/dist/validation-BMImFJ11.mjs.map +0 -1
- package/dist/version-Bii3suaO.mjs +0 -7
- package/dist/version-Bii3suaO.mjs.map +0 -1
- package/dist/widgets-D3gJ10xU.mjs +0 -122
- package/dist/widgets-D3gJ10xU.mjs.map +0 -1
- package/dist/wxr-taxonomies-B2Og_6rU.d.mts +0 -34
- package/dist/wxr-taxonomies-B2Og_6rU.d.mts.map +0 -1
- package/dist/wxr-taxonomies-Cxngsjwo.mjs +0 -406
- package/dist/wxr-taxonomies-Cxngsjwo.mjs.map +0 -1
- package/dist/zod-generator-BuYSQJB7.mjs +0 -331
- package/dist/zod-generator-BuYSQJB7.mjs.map +0 -1
- /package/dist/{api-tokens-BfYts-sq.mjs → api-tokens-DS1VzN7_.mjs} +0 -0
- /package/dist/{ssrf-Dg3cIT-b.mjs → ssrf-BRpTDMV6.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-k--LneIF.mjs","names":[],"sources":["../src/plugins/types.ts"],"sourcesContent":["/**\n * Plugin System Types v2\n *\n * New plugin API with:\n * - Single unified context shape for all hooks and routes\n * - Paginated storage queries (no async iterators)\n * - Unified KV API (replaces settings + options)\n * - Explicit ctx.http and ctx.log\n *\n */\n\nimport type { Permission } from \"@emdash-cms/auth\";\nimport type { ConfirmDialog, Element, PluginUiContext } from \"@emdash-cms/blocks\";\n// The plugin capability vocabulary, the legacy-rename map, and the manifest\n// shape are authored once in @emdash-cms/plugin-types and shared between core\n// (the manifest reader at install/runtime) and @emdash-cms/plugin-cli (the\n// manifest writer at bundle/publish time).\n//\n// We import-and-re-export here so existing internal callers keep working\n// (e.g. `import { PluginCapability } from \"../plugins/types.js\"`).\nimport {\n\tCAPABILITY_RENAMES,\n\tcapabilitiesToDeclaredAccess,\n\tdeclaredAccessToCapabilities,\n\tisDeprecatedCapability,\n\tnormalizeCapabilities,\n\tnormalizeCapability,\n\ttype CurrentPluginCapability,\n\ttype DeclaredAccess,\n\ttype DeprecatedPluginCapability,\n\ttype ManifestHookEntry,\n\ttype ManifestMcpTool,\n\ttype ManifestRouteEntry,\n\ttype PluginMcpManifestConfig,\n\ttype PluginCapability,\n\ttype PluginEditorDraftAccess,\n\ttype PluginEditorDraftFieldSelector,\n\ttype PluginFormData,\n\ttype PluginRouteBodyMode,\n\ttype PluginRouteQuery,\n\ttype PluginRouteRequest,\n\ttype PluginStorageConfig,\n\ttype RouteOptions,\n\ttype StorageCollectionConfig,\n} from \"@emdash-cms/plugin-types\";\nimport type { JSX } from \"astro/jsx-runtime\";\nimport type { z } from \"astro/zod\";\n// =============================================================================\n// Core Types\n// =============================================================================\n\nimport type { ContentFieldFilters } from \"../content-list-query.js\";\nimport type { FieldType, FieldValidation, FieldWidgetOptions } from \"../schema/types.js\";\n\nexport type {\n\tContentFieldFilterScalar,\n\tContentFieldFilterValue,\n\tContentFieldFilters,\n\tContentFieldInFilter,\n\tContentFieldRangeFilter,\n} from \"../content-list-query.js\";\n\nexport {\n\tCAPABILITY_RENAMES,\n\tcapabilitiesToDeclaredAccess,\n\tdeclaredAccessToCapabilities,\n\tisDeprecatedCapability,\n\tnormalizeCapabilities,\n\tnormalizeCapability,\n\ttype CurrentPluginCapability,\n\ttype DeclaredAccess,\n\ttype DeprecatedPluginCapability,\n\ttype ManifestHookEntry,\n\ttype ManifestMcpTool,\n\ttype ManifestRouteEntry,\n\ttype PluginMcpManifestConfig,\n\ttype PluginCapability,\n\ttype PluginEditorDraftAccess,\n\ttype PluginEditorDraftFieldSelector,\n\ttype PluginStorageConfig,\n\ttype StorageCollectionConfig,\n};\n\nexport const PLUGIN_CAPABILITY_IMPLICATIONS: ReadonlyArray<\n\treadonly [PluginCapability, PluginCapability]\n> = [\n\t[\"content:write\", \"content:read\"],\n\t[\"content:revisions:read\", \"content:read\"],\n\t[\"taxonomies:write\", \"taxonomies:read\"],\n\t[\"content:publish\", \"content:read\"],\n\t[\"media:write\", \"media:read\"],\n\t[\"comments:moderate\", \"comments:read\"],\n\t[\"redirects:write\", \"redirects:read\"],\n\t[\"network:request:unrestricted\", \"network:request\"],\n];\n\nexport function normalizePluginCapabilities(\n\tcapabilities: readonly PluginCapability[],\n): PluginCapability[];\nexport function normalizePluginCapabilities(capabilities: readonly string[]): string[];\nexport function normalizePluginCapabilities(capabilities: readonly string[]): string[] {\n\tconst normalized = new Set(normalizeCapabilities(capabilities));\n\tfor (const [granted, implied] of PLUGIN_CAPABILITY_IMPLICATIONS) {\n\t\tif (normalized.has(granted)) normalized.add(implied);\n\t}\n\treturn [...normalized];\n}\n\n// =============================================================================\n// Storage Types\n// =============================================================================\n//\n// `StorageCollectionConfig` and `PluginStorageConfig` are re-exported above\n// from `@emdash-cms/plugin-types`. The manifest carries these shapes\n// verbatim; both this package (reader) and plugin-cli (writer) agree on\n// the same types via the shared package.\n\n/**\n * Query filter operators\n */\nexport interface RangeFilter {\n\tgt?: number | string;\n\tgte?: number | string;\n\tlt?: number | string;\n\tlte?: number | string;\n}\n\nexport interface InFilter {\n\tin: Array<string | number>;\n}\n\nexport interface StartsWithFilter {\n\tstartsWith: string;\n}\n\n/**\n * Where clause value types\n */\nexport type WhereValue =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| RangeFilter\n\t| InFilter\n\t| StartsWithFilter;\n\n/**\n * Where clause for storage queries\n */\nexport type WhereClause = Record<string, WhereValue>;\n\n/**\n * Query options for storage.query()\n */\nexport interface QueryOptions {\n\twhere?: WhereClause;\n\torderBy?: Record<string, \"asc\" | \"desc\">;\n\t/** Default 50, max 100 */\n\tlimit?: number;\n\tcursor?: string;\n}\n\n/**\n * Paginated result (used by storage.query, content.list, media.list)\n */\nexport interface PaginatedResult<T> {\n\titems: T[];\n\tcursor?: string;\n\thasMore: boolean;\n}\n\nexport interface VersionedValue<T = unknown> {\n\tvalue: T;\n\t/** Opaque host revision, valid only for the key from which it was read. */\n\trevision: string;\n}\n\nexport type ConditionalWriteResult = { applied: true; revision: string } | { applied: false };\n\nexport interface ConditionalDeleteResult {\n\tapplied: boolean;\n}\n\n/**\n * A single per-field integer delta for {@link StorageCollection.updateIf}.\n *\n * `inc`/`dec` values must be safe integers, enforced at runtime with\n * `Number.isSafeInteger` (which also rejects `NaN`/`Infinity`), because a TS\n * `number` cannot forbid float literals. Deltas are applied entirely in-SQL\n * over the stored value with `COALESCE(<value>, 0) ± n`, so a delta on a\n * missing or JSON-`null` field starts from `0` (never corrupts the document).\n *\n * `updateIf` does NOT clamp: a `dec` can drive a field negative when the\n * `where` guard doesn't cover the delta magnitude (e.g. stock `2` with\n * `where: { stock: { gte: 1 } }` and `delta: { stock: { dec: 3 } }` → `-1`,\n * `applied: true`). The guard is the caller's responsibility — pair a `dec: k`\n * with a `gte: k` guard to prevent underflow.\n */\nexport type NumericDelta = { inc: number } | { dec: number };\n\n/**\n * Arguments to {@link StorageCollection.updateIf}.\n *\n * `where` reuses the {@link QueryOptions} `WhereClause` verbatim — the guard is\n * evaluated in-SQL with the same numeric-correct, total comparisons as\n * `query()`. An empty `where: {}` emits no guard, i.e. it matches the row\n * unconditionally (update-if-row-exists) — a footgun in the no-oversell case,\n * where a real predicate (e.g. `{ stock: { gte: 1 } }`) is what you want.\n *\n * At least one of `set` / `delta` must be present (a runtime error is thrown\n * otherwise). A field may not appear in both `set` and `delta` in the same\n * call. `set` and `delta` are separate arguments (not a union) so a wholesale\n * value that happens to look like `{ inc: 5 }` is never mistaken for a delta.\n */\nexport interface UpdateIfArgs<T> {\n\t/**\n\t * Guard evaluated in-SQL; identical semantics to `query({ where })`. An\n\t * empty `{}` means \"match the row unconditionally (no guard)\".\n\t */\n\twhere: WhereClause;\n\t/** Wholesale field values merged into the stored JSON document. */\n\tset?: Partial<T>;\n\t/** Per-field integer deltas applied in-SQL (`COALESCE(base, 0) ± n`). */\n\tdelta?: { [K in keyof T]?: NumericDelta };\n}\n\n/**\n * Result of {@link StorageCollection.updateIf}.\n *\n * `applied: false` intentionally conflates \"row absent\" and \"guard failed\": a\n * single-statement guarded `UPDATE` cannot distinguish them, and the caller\n * should not need to. `updateIf` is update-only — it never inserts a missing\n * row.\n */\nexport type UpdateIfResult<T> = { applied: true; data: T } | { applied: false };\n\n/**\n * Storage collection interface - the API exposed to plugins\n * No async iterators - all operations return promises with pagination\n */\nexport interface StorageCollection<T = unknown> {\n\t// Basic CRUD\n\tget(id: string): Promise<T | null>;\n\tput(id: string, data: T): Promise<void>;\n\tdelete(id: string): Promise<boolean>;\n\texists(id: string): Promise<boolean>;\n\t/** A stored JSON null returns an envelope with value: null; only an absent row returns null. */\n\tgetVersioned(id: string): Promise<VersionedValue<T> | null>;\n\t/** A null expected revision creates only when absent. Errors reject; conflicts return applied: false. */\n\tcompareAndSet(\n\t\tid: string,\n\t\texpectedRevision: string | null,\n\t\tdata: T,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(id: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\n\t// Batch operations\n\tgetMany(ids: string[]): Promise<Map<string, T>>;\n\tputMany(items: Array<{ id: string; data: T }>): Promise<void>;\n\tdeleteMany(ids: string[]): Promise<number>;\n\n\t// Query - always paginated\n\tquery(options?: QueryOptions): Promise<PaginatedResult<{ id: string; data: T }>>;\n\tcount(where?: WhereClause): Promise<number>;\n\n\t// Conditional write (single-statement, atomic per row).\n\t/**\n\t * Predicate-guarded atomic update. Applies `set`/`delta` to the row `id`\n\t * only if it exists and the `where` guard matches, in a single guarded\n\t * `UPDATE … RETURNING`. This is the no-oversell primitive: the guard and the\n\t * arithmetic live in one statement, so N concurrent guarded decrements\n\t * serialize correctly. `applied: false` means the row was absent OR the\n\t * guard failed (the two are intentionally indistinguishable). Non-object\n\t * documents, invalid counters and unsafe arithmetic results also fail the\n\t * guard. Never inserts.\n\t *\n\t * Serialization failures and deadlocks throw `StorageSerializationError`.\n\t * Retry the write with a bounded policy; restart an explicit transaction\n\t * before retrying its operations.\n\t */\n\tupdateIf(id: string, args: UpdateIfArgs<T>): Promise<UpdateIfResult<T>>;\n}\n\n/**\n * Plugin storage context - typed based on declared collections\n */\nexport type PluginStorage<T extends PluginStorageConfig> = {\n\t[K in keyof T]: StorageCollection;\n};\n\n// =============================================================================\n// Context APIs\n// =============================================================================\n\n/**\n * Plugin-scoped key-value state.\n *\n * Convention:\n * - `state:*` - Internal plugin state (not shown to users)\n * - `cache:*` - Reusable computed or remote data\n *\n * The `settings:*` namespace remains a compatibility alias through EmDash\n * 0.x. New code uses `PluginContext.settings` for user configuration.\n */\nexport interface KVAccess {\n\tget<T>(key: string): Promise<T | null>;\n\tgetVersioned<T>(key: string): Promise<VersionedValue<T> | null>;\n\t/** A null expected revision creates only when absent. Errors reject; conflicts return applied: false. */\n\tcompareAndSet(\n\t\tkey: string,\n\t\texpectedRevision: string | null,\n\t\tvalue: unknown,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(key: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<boolean>;\n\tlist(prefix?: string): Promise<Array<{ key: string; value: unknown }>>;\n}\n\n/** Plugin settings. Fields declared as `secret` in `admin.settingsSchema` are encrypted. */\nexport interface SettingsAccess {\n\tget<T>(key: string): Promise<T | null>;\n\tgetVersioned<T>(key: string): Promise<VersionedValue<T> | null>;\n\tcompareAndSet(\n\t\tkey: string,\n\t\texpectedRevision: string | null,\n\t\tvalue: unknown,\n\t): Promise<ConditionalWriteResult>;\n\tcompareAndDelete(key: string, expectedRevision: string): Promise<ConditionalDeleteResult>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<boolean>;\n\tlist(prefix?: string): Promise<Array<{ key: string; value: unknown }>>;\n}\n\n/**\n * SEO metadata for a content item, as stored in the core SEO panel.\n *\n * Only present on items in collections with `has_seo = 1`. For collections\n * without SEO enabled, `ContentItem.seo` is `undefined`.\n */\nexport interface ContentItemSeo {\n\ttitle: string | null;\n\tdescription: string | null;\n\timage: string | null;\n\tcanonical: string | null;\n\tnoIndex: boolean;\n}\n\n/**\n * SEO input accepted by content write operations.\n *\n * All fields are optional — only fields that are present overwrite existing\n * values. An empty object is treated as a no-op.\n */\nexport interface ContentItemSeoInput {\n\ttitle?: string | null;\n\tdescription?: string | null;\n\timage?: string | null;\n\tcanonical?: string | null;\n\tnoIndex?: boolean;\n}\n\n/**\n * Content item returned from content API\n */\nexport interface ContentItem {\n\tid: string;\n\ttype: string;\n\tslug: string | null;\n\tstatus: string;\n\tlocale: string | null;\n\tdata: Record<string, unknown>;\n\t/**\n\t * SEO metadata, populated when the collection has SEO enabled\n\t * (`has_seo = 1`). `undefined` for non-SEO collections.\n\t */\n\tseo?: ContentItemSeo;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tpublishedAt: string | null;\n\t/** Scheduled publication time, if set (e.g. scheduled items or scheduled draft changes). */\n\tscheduledAt?: string | null;\n\tauthorId?: string | null;\n\ttranslationGroup?: string | null;\n\tliveRevisionId?: string | null;\n\tdraftRevisionId?: string | null;\n\tversion?: number;\n}\n\nexport interface ContentTranslationSummary {\n\tid: string;\n\tlocale: string | null;\n\tslug: string | null;\n\tstatus: string;\n\tupdatedAt: string;\n}\n\nexport interface ContentRevisionInfo {\n\tid: string;\n\tcollection: string;\n\tentryId: string;\n\tdata: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface FieldSchemaInfo {\n\tslug: string;\n\tlabel: string;\n\ttype: FieldType;\n\trequired: boolean;\n\tunique: boolean;\n\tdefault?: unknown;\n\tvalidation?: FieldValidation;\n\twidget?: string;\n\toptions?: FieldWidgetOptions;\n\tsearchable: boolean;\n\tindexed: boolean;\n\ttranslatable: boolean;\n\tsortOrder: number;\n}\n\nexport interface CollectionSchemaInfo {\n\tslug: string;\n\tlabel: string;\n\tlabelSingular: string | null;\n\tdescription: string | null;\n\tsupports: string[];\n\thasSeo: boolean;\n\ttitleField: string | null;\n\tdateField: string | null;\n\turlPattern: string | null;\n\troutable: boolean;\n\thidden: boolean;\n\tfields: FieldSchemaInfo[];\n}\n\nexport interface SchemaAccess {\n\tlistCollections(): Promise<CollectionSchemaInfo[]>;\n\tgetCollection(slug: string): Promise<CollectionSchemaInfo | null>;\n}\n\nexport interface ContentListWhere {\n\t/** Exact match on `status` (e.g. `\"published\"`, `\"draft\"`). */\n\tstatus?: string;\n\t/** Exact match on `locale` (e.g. `\"en\"`, `\"fr-CA\"`). */\n\tlocale?: string;\n\t/** AND-combined filters over custom fields explicitly marked as indexed. */\n\tfieldFilters?: ContentFieldFilters;\n}\n\n/**\n * Content list options\n */\nexport interface ContentListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\torderBy?: Record<string, \"asc\" | \"desc\">;\n\twhere?: ContentListWhere;\n}\n\n/**\n * Input accepted by `content.create` / `content.update`.\n *\n * Most entries are field slugs mapped to their values. The reserved `seo`\n * key is extracted and routed to the core SEO panel (the `_emdash_seo`\n * table), matching the shape accepted by the REST API. Passing `seo` for a\n * collection that does not have SEO enabled throws a validation error.\n */\nexport type ContentWriteInput = Record<string, unknown> & {\n\tseo?: ContentItemSeoInput;\n};\n\n/** Options accepted by `content.create`. */\nexport interface ContentCreateOptions {\n\t/** Locale for the new content row. Defaults to the configured site locale, then `en`. */\n\tlocale?: string;\n\t/** Existing row in the same collection whose translation group the new row joins. */\n\ttranslationOf?: string;\n}\n\nexport type PluginContentCreateCallback = (\n\tpluginId: string,\n\tcollection: string,\n\tdata: ContentWriteInput,\n\toptions?: ContentCreateOptions & {\n\t\t/** Save-hook origin supplied by sandbox transports to prevent hook re-entry. */\n\t\toriginHook?: \"content:beforeSave\" | \"content:afterSave\";\n\t\tsandboxOrigin?: true;\n\t},\n) => Promise<ContentItem>;\n\n/**\n * Taxonomy definition returned from the taxonomy API (e.g. \"category\", \"tag\").\n */\nexport interface TaxonomyDefInfo {\n\tname: string;\n\tlabel: string;\n\tlabelSingular: string | null;\n\thierarchical: boolean;\n\t/** Collections this taxonomy is attached to (e.g. `[\"posts\"]`). */\n\tcollections: string[];\n\tlocale: string;\n}\n\n/**\n * Taxonomy term returned from the taxonomy API. Flat shape — for hierarchical\n * taxonomies the tree is reconstructed via `parentId` (which stores the\n * parent's locale-agnostic `translationGroup`).\n */\nexport interface TaxonomyTermInfo {\n\tid: string;\n\t/** Taxonomy name this term belongs to (e.g. \"category\"). */\n\ttaxonomy: string;\n\tslug: string;\n\tlabel: string;\n\tparentId: string | null;\n\t/** Term metadata as edited in the admin (`description` etc.). */\n\tdata: Record<string, unknown> | null;\n\tlocale: string;\n\ttranslationGroup: string | null;\n}\n\n/**\n * Options accepted by taxonomy read operations. Omitting `locale` returns\n * rows for every locale.\n */\nexport interface TaxonomyReadOptions {\n\tlocale?: string;\n}\n\nexport interface TaxonomyTermCreateInput {\n\tlabel: string;\n\tslug?: string;\n\tparentId?: string | null;\n\tdescription?: string;\n\tlocale?: string;\n\ttranslationOf?: string;\n}\n\n/**\n * Content access interface - capability-gated\n */\nexport interface ContentAccess {\n\t// Read operations (requires read:content)\n\tget(collection: string, id: string): Promise<ContentItem | null>;\n\tlist(collection: string, options?: ContentListOptions): Promise<PaginatedResult<ContentItem>>;\n\tgetTranslations?(\n\t\tcollection: string,\n\t\tid: string,\n\t): Promise<{ translationGroup: string; translations: ContentTranslationSummary[] }>;\n\tgetPublicUrl?(collection: string, id: string): Promise<string | null>;\n\tlistRevisions?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions?: { limit?: number },\n\t): Promise<ContentRevisionInfo[]>;\n\tgetRevision?(\n\t\tcollection: string,\n\t\tid: string,\n\t\trevisionId: string,\n\t): Promise<ContentRevisionInfo | null>;\n\n\t// Write operations (requires write:content) - optional on interface\n\tcreate?(\n\t\tcollection: string,\n\t\tdata: ContentWriteInput,\n\t\toptions?: ContentCreateOptions,\n\t): Promise<ContentItem>;\n\tupdate?(collection: string, id: string, data: ContentWriteInput): Promise<ContentItem>;\n\tdelete?(collection: string, id: string): Promise<boolean>;\n\tgetVersioned?(collection: string, id: string): Promise<VersionedContentItem | null>;\n\tpublish?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunpublish?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tschedule?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { scheduledAt: string; _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunschedule?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tgetTrashedVersioned?(collection: string, id: string): Promise<VersionedContentItem | null>;\n\trestore?(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n}\n\nexport interface VersionedContentItem {\n\titem: ContentItem;\n\t_rev: string;\n}\n\nexport interface ContentPublicationAccess extends ContentAccess {\n\tgetVersioned(collection: string, id: string): Promise<VersionedContentItem | null>;\n\tpublish(collection: string, id: string, options: { _rev: string }): Promise<VersionedContentItem>;\n\tunpublish(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n\tschedule(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { scheduledAt: string; _rev: string },\n\t): Promise<VersionedContentItem>;\n\tunschedule(\n\t\tcollection: string,\n\t\tid: string,\n\t\toptions: { _rev: string },\n\t): Promise<VersionedContentItem>;\n}\n\nexport interface ContentRestoreAccess {\n\tgetTrashedVersioned(collection: string, id: string): Promise<VersionedContentItem | null>;\n\trestore(collection: string, id: string, options: { _rev: string }): Promise<VersionedContentItem>;\n}\n\n/**\n * Taxonomy access interface — capability-gated on `taxonomies:read`.\n */\nexport interface TaxonomyAccess {\n\t/** List taxonomy definitions. */\n\tgetAll(options?: TaxonomyReadOptions): Promise<TaxonomyDefInfo[]>;\n\t/** All terms of a taxonomy, ordered by label. */\n\tgetTerms(taxonomy: string, options?: TaxonomyReadOptions): Promise<TaxonomyTermInfo[]>;\n\t/** Terms assigned to a content entry, optionally scoped to one taxonomy. */\n\tgetEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\toptions?: TaxonomyReadOptions & { taxonomy?: string },\n\t): Promise<TaxonomyTermInfo[]>;\n\tcreateTerm?(taxonomy: string, input: TaxonomyTermCreateInput): Promise<TaxonomyTermInfo>;\n\taddEntryTerms?(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n\tremoveEntryTerms?(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n}\n\n/** Taxonomy mutations available with `taxonomies:write`. */\nexport interface TaxonomyAccessWithWrite extends TaxonomyAccess {\n\tcreateTerm(taxonomy: string, input: TaxonomyTermCreateInput): Promise<TaxonomyTermInfo>;\n\taddEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n\tremoveEntryTerms(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomy: string,\n\t\ttermIds: string[],\n\t): Promise<TaxonomyTermInfo[]>;\n}\n\nexport type RedirectStatus = 301 | 302 | 307 | 308 | 410 | 451;\n\nexport interface RedirectInfo {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\ttype: RedirectStatus;\n\tisPattern: boolean;\n\tenabled: boolean;\n\thits: number;\n\tlastHitAt: string | null;\n\tgroupName: string | null;\n\tauto: boolean;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface VersionedRedirect {\n\tredirect: RedirectInfo;\n\t/** Opaque host revision. Pass it back unchanged for update or delete. */\n\t_rev: string;\n}\n\nexport interface RedirectListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tsearch?: string;\n\tgroup?: string;\n\tenabled?: boolean;\n\tauto?: boolean;\n}\n\nexport interface RedirectCreateInput {\n\tsource: string;\n\tdestination?: string;\n\ttype?: RedirectStatus;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n}\n\nexport interface RedirectUpdateInput {\n\tsource?: string;\n\tdestination?: string;\n\ttype?: RedirectStatus;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n}\n\nexport interface RedirectAccess {\n\tlist(options?: RedirectListOptions): Promise<PaginatedResult<RedirectInfo>>;\n\tget(id: string): Promise<VersionedRedirect | null>;\n\tcreate?(input: RedirectCreateInput): Promise<VersionedRedirect>;\n\tupdate?(id: string, input: RedirectUpdateInput & { _rev: string }): Promise<VersionedRedirect>;\n\tdelete?(id: string, options: { _rev: string }): Promise<boolean>;\n}\n\nexport interface RedirectAccessWithWrite extends RedirectAccess {\n\tcreate(input: RedirectCreateInput): Promise<VersionedRedirect>;\n\tupdate(id: string, input: RedirectUpdateInput & { _rev: string }): Promise<VersionedRedirect>;\n\tdelete(id: string, options: { _rev: string }): Promise<boolean>;\n}\n\n/**\n * Full content access with write operations\n */\nexport interface ContentAccessWithWrite extends ContentAccess {\n\tcreate(\n\t\tcollection: string,\n\t\tdata: ContentWriteInput,\n\t\toptions?: ContentCreateOptions,\n\t): Promise<ContentItem>;\n\tupdate(collection: string, id: string, data: ContentWriteInput): Promise<ContentItem>;\n\tdelete(collection: string, id: string): Promise<boolean>;\n}\n\n/**\n * Media item returned from media API\n */\nexport interface MediaItem {\n\tid: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number | null;\n\turl: string;\n\tcreatedAt: string;\n\twidth?: number | null;\n\theight?: number | null;\n\talt?: string | null;\n\tcaption?: string | null;\n\tfocalX?: number | null;\n\tfocalY?: number | null;\n\tblurhash?: string | null;\n\tdominantColor?: string | null;\n\tfolderId?: string | null;\n\tstatus?: \"ready\";\n}\n\nexport interface MediaBytes {\n\tbytes: Uint8Array;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number;\n\tcontentHash?: string;\n}\n\nexport interface MediaMetadataPatch {\n\talt?: string | null;\n\tcaption?: string | null;\n\tfocalX?: number | null;\n\tfocalY?: number | null;\n}\n\n/**\n * Media list options\n */\nexport interface MediaListOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tmimeType?: string; // Filter by mime type prefix, e.g., \"image/\"\n}\n\n/**\n * Media access interface - capability-gated\n */\nexport interface MediaAccess {\n\t// Read operations (requires read:media)\n\tget(id: string): Promise<MediaItem | null>;\n\tlist(options?: MediaListOptions): Promise<PaginatedResult<MediaItem>>;\n\t/** Read ready media bytes, bounded by the caller's limit and the host maximum. */\n\treadBytes?(id: string, options?: { maxBytes?: number }): Promise<MediaBytes>;\n\t/** Change only alt text, caption, or the complete focal-point pair. */\n\tupdateMetadata?(id: string, patch: MediaMetadataPatch): Promise<MediaItem>;\n\n\t// Write operations (requires write:media) - optional on interface\n\tgetUploadUrl?(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t): Promise<{ uploadUrl: string; mediaId: string }>;\n\t/**\n\t * Upload media bytes directly. Preferred in sandboxed mode where\n\t * plugins cannot make external requests to a presigned URL.\n\t * Returns the created media item.\n\t */\n\tupload?(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t\tbytes: ArrayBuffer,\n\t): Promise<{ mediaId: string; storageKey: string; url: string }>;\n\tdelete?(id: string): Promise<boolean>;\n}\n\n/**\n * Full media access with write operations\n */\nexport interface MediaAccessWithWrite extends MediaAccess {\n\tgetUploadUrl(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t): Promise<{ uploadUrl: string; mediaId: string }>;\n\tupload(\n\t\tfilename: string,\n\t\tcontentType: string,\n\t\tbytes: ArrayBuffer,\n\t): Promise<{ mediaId: string; storageKey: string; url: string }>;\n\tdelete(id: string): Promise<boolean>;\n}\n\n/**\n * HTTP client interface - requires network:request capability\n */\nexport interface HttpAccess {\n\t/**\n\t * Fetch an allowed external URL and return a buffered response.\n\t * Decoded request and response bodies are each limited to 8 MiB.\n\t */\n\tfetch(url: string, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Logger interface - always available\n */\nexport interface LogAccess {\n\tdebug(message: string, data?: unknown): void;\n\tinfo(message: string, data?: unknown): void;\n\twarn(message: string, data?: unknown): void;\n\terror(message: string, data?: unknown): void;\n}\n\n// =============================================================================\n// Site & User Access\n// =============================================================================\n\n/**\n * Site information available to all plugins\n */\nexport interface SiteInfo {\n\t/** Site name (from settings) */\n\tname: string;\n\t/** Site URL (from settings or request) */\n\turl: string;\n\t/** Site locale (from settings, defaults to \"en\") */\n\tlocale: string;\n\t/**\n\t * Astro's `trailingSlash` routing policy, from the host's Astro config.\n\t * Plugins that build absolute URLs (sitemap, canonical, hreflang) should\n\t * honor this so the URLs they emit match what the site serves. `createSiteInfo`\n\t * always populates it (defaulting to `\"ignore\"`, Astro's default); it is\n\t * optional on the type so pre-existing `SiteInfo` construction stays valid.\n\t */\n\ttrailingSlash?: \"always\" | \"never\" | \"ignore\";\n}\n\n/**\n * Read-only user information exposed to plugins.\n * Sensitive fields (password hashes, sessions, passkeys) are excluded.\n */\nexport interface UserInfo {\n\tid: string;\n\temail: string;\n\tname: string | null;\n\trole: number;\n\tcreatedAt: string;\n}\n\n/**\n * User access interface - requires read:users capability\n */\nexport interface UserAccess {\n\t/** Get a user by ID */\n\tget(id: string): Promise<UserInfo | null>;\n\t/** Get a user by email */\n\tgetByEmail(email: string): Promise<UserInfo | null>;\n\t/** List users with optional filters */\n\tlist(opts?: { role?: number; limit?: number; cursor?: string }): Promise<{\n\t\titems: UserInfo[];\n\t\tnextCursor?: string;\n\t}>;\n}\n\nexport type PluginCommentStatus = \"approved\" | \"pending\" | \"spam\";\n\n/** Comment data exposed by the explicit personal-data `comments:read` capability. */\nexport interface PluginComment {\n\tid: string;\n\tcollection: string;\n\tcontentId: string;\n\tparentId: string | null;\n\tauthorName: string;\n\tauthorEmail: string;\n\tbody: string;\n\tstatus: PluginCommentStatus;\n\tipHash: string | null;\n\tuserAgent: string | null;\n\tmoderationMetadata: Record<string, unknown> | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface CommentListOptions {\n\tstatus?: PluginCommentStatus;\n\tcollection?: string;\n\tcontentId?: string;\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface CommentCountOptions {\n\tstatus?: PluginCommentStatus;\n\tcollection?: string;\n\tcontentId?: string;\n}\n\nexport interface CommentAccess {\n\tget(id: string): Promise<PluginComment | null>;\n\tlist(options?: CommentListOptions): Promise<PaginatedResult<PluginComment>>;\n\tcount(options?: CommentCountOptions): Promise<number>;\n\tsetStatus?(\n\t\tid: string,\n\t\tstatus: PluginCommentStatus,\n\t\toptions: { expectedStatus: PluginCommentStatus },\n\t): Promise<PluginComment>;\n}\n\n// =============================================================================\n// Plugin Context\n// =============================================================================\n\n/**\n * The unified plugin context - same shape for all hooks and routes\n */\nexport interface PluginContext<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\t/** Plugin metadata */\n\tplugin: {\n\t\tid: string;\n\t\tversion: string;\n\t};\n\n\t/** Storage collections - only if plugin declares storage */\n\tstorage: PluginStorage<TStorage>;\n\n\t/** Key-value store for internal state */\n\tkv: KVAccess;\n\n\t/** Plugin settings. Secret schema fields are encrypted by the host. */\n\tsettings: SettingsAccess;\n\n\t/** Content access - only if read:content or write:content capability */\n\tcontent?: ContentAccess | ContentAccessWithWrite;\n\t/** Schema discovery - only if schema:read capability */\n\tschema?: SchemaAccess;\n\n\t/** Taxonomy access - only if a taxonomy capability is declared. */\n\ttaxonomies?: TaxonomyAccess | TaxonomyAccessWithWrite;\n\n\t/** Redirect access - only if redirects:read or redirects:write capability */\n\tredirects?: RedirectAccess | RedirectAccessWithWrite;\n\n\t/** Media access - only if read:media or write:media capability */\n\tmedia?: MediaAccess | MediaAccessWithWrite;\n\n\t/** HTTP client - only if network:request capability */\n\thttp?: HttpAccess;\n\n\t/** Logger - always available */\n\tlog: LogAccess;\n\n\t/** Site information - always available */\n\tsite: SiteInfo;\n\n\t/** URL helper - generates absolute URLs from paths. Always available. */\n\turl(path: string): string;\n\n\t/** User access - only if read:users capability */\n\tusers?: UserAccess;\n\n\t/** Comment access — only if comments:read or comments:moderate is declared. */\n\tcomments?: CommentAccess;\n\n\t/** Cron task scheduling - always available, scoped to plugin */\n\tcron?: CronAccess;\n\n\t/** Email access - only if email:send capability and a provider is configured */\n\temail?: EmailAccess;\n}\n\n// =============================================================================\n// Cron Types\n// =============================================================================\n\n/**\n * Cron access interface �� always available on plugin context, scoped to plugin.\n */\nexport interface CronAccess {\n\t/** Schedule a recurring or one-shot task */\n\tschedule(name: string, opts: { schedule: string; data?: Record<string, unknown> }): Promise<void>;\n\t/** Cancel a scheduled task */\n\tcancel(name: string): Promise<void>;\n\t/** List this plugin's scheduled tasks */\n\tlist(): Promise<CronTaskInfo[]>;\n}\n\n/**\n * Task info returned from CronAccess.list()\n */\nexport interface CronTaskInfo {\n\tname: string;\n\tschedule: string;\n\tnextRunAt: string;\n\tlastRunAt: string | null;\n}\n\n/**\n * Event passed to the `cron` hook handler\n */\nexport interface CronEvent {\n\tname: string;\n\tdata?: Record<string, unknown>;\n\tscheduledAt: string;\n}\n\n/**\n * Cron hook handler type\n */\nexport type CronHandler = (event: CronEvent, ctx: PluginContext) => Promise<void>;\n\n// =============================================================================\n// Email Types\n// =============================================================================\n\n/**\n * Email access interface — requires `email:send` capability.\n * Undefined when no `email:deliver` provider is configured.\n *\n * Related capabilities:\n * - `email:send` — grants ctx.email (this interface)\n * - `email:provide` — allows registering the `email:deliver` exclusive hook\n * - `email:intercept` — allows registering `email:beforeSend` / `email:afterSend` hooks\n */\nexport interface EmailAccess {\n\tsend(message: EmailMessage): Promise<void>;\n}\n\n/**\n * Email message shape\n */\nexport interface EmailMessage {\n\tto: string;\n\tsubject: string;\n\ttext: string;\n\thtml?: string;\n}\n\n/**\n * Event passed to email:beforeSend hooks (middleware — transform, validate, cancel)\n */\nexport interface EmailBeforeSendEvent {\n\tmessage: EmailMessage;\n\t/** Where the email originated — \"system\" for auth emails, plugin ID for plugin emails */\n\tsource: string;\n}\n\n/**\n * Event passed to email:deliver hook (exclusive — exactly one provider delivers)\n */\nexport interface EmailDeliverEvent {\n\tmessage: EmailMessage;\n\tsource: string;\n}\n\n/**\n * Event passed to email:afterSend hooks (logging, analytics, fire-and-forget)\n */\nexport interface EmailAfterSendEvent {\n\tmessage: EmailMessage;\n\tsource: string;\n}\n\n/**\n * Handler type for email:beforeSend hooks.\n * Returns modified message, or false to cancel delivery.\n */\nexport type EmailBeforeSendHandler = (\n\tevent: EmailBeforeSendEvent,\n\tctx: PluginContext,\n) => Promise<EmailMessage | false>;\n\n/**\n * Handler type for email:deliver hooks (exclusive provider).\n */\nexport type EmailDeliverHandler = (event: EmailDeliverEvent, ctx: PluginContext) => Promise<void>;\n\n/**\n * Handler type for email:afterSend hooks (fire-and-forget).\n */\nexport type EmailAfterSendHandler = (\n\tevent: EmailAfterSendEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n// =============================================================================\n// Comment Types\n// =============================================================================\n\n/**\n * Collection comment settings (read from _emdash_collections)\n */\nexport interface CollectionCommentSettings {\n\tcommentsEnabled: boolean;\n\tcommentsModeration: \"all\" | \"first_time\" | \"none\";\n\tcommentsClosedAfterDays: number;\n\tcommentsAutoApproveUsers: boolean;\n}\n\n/**\n * Event passed to comment:beforeCreate hooks (middleware — transform, enrich, reject)\n */\nexport interface CommentBeforeCreateEvent {\n\tcomment: {\n\t\tcollection: string;\n\t\tcontentId: string;\n\t\tparentId: string | null;\n\t\tauthorName: string;\n\t\tauthorEmail: string;\n\t\tauthorUserId: string | null;\n\t\tbody: string;\n\t\tipHash: string | null;\n\t\tuserAgent: string | null;\n\t};\n\t/** Metadata bag — plugins can attach signals for the moderator */\n\tmetadata: Record<string, unknown>;\n}\n\n/**\n * Event passed to comment:moderate hook (exclusive — decides initial status)\n */\nexport interface CommentModerateEvent {\n\tcomment: CommentBeforeCreateEvent[\"comment\"];\n\tmetadata: Record<string, unknown>;\n\tcollectionSettings: CollectionCommentSettings;\n\t/** Number of prior approved comments from this email address */\n\tpriorApprovedCount: number;\n}\n\n/**\n * Moderation decision returned by the comment:moderate handler\n */\nexport interface ModerationDecision {\n\tstatus: \"approved\" | \"pending\" | \"spam\";\n\t/** Optional reason for admin visibility */\n\treason?: string;\n}\n\n/**\n * Stored comment shape (full record with id, status, timestamps)\n */\nexport interface StoredComment {\n\tid: string;\n\tcollection: string;\n\tcontentId: string;\n\tparentId: string | null;\n\tauthorName: string;\n\tauthorEmail: string;\n\tauthorUserId: string | null;\n\tbody: string;\n\tstatus: string;\n\tmoderationMetadata: Record<string, unknown> | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Event passed to comment:afterCreate hooks (fire-and-forget)\n */\nexport interface CommentAfterCreateEvent {\n\tcomment: StoredComment;\n\tmetadata: Record<string, unknown>;\n\t/** The content item the comment is on */\n\tcontent: { id: string; collection: string; slug: string; title?: string };\n\t/** The content author (for notifications) */\n\tcontentAuthor?: { id: string; name: string | null; email: string };\n}\n\n/**\n * Event passed to comment:afterModerate hooks (fire-and-forget, admin status change)\n */\nexport interface CommentAfterModerateEvent {\n\tcomment: StoredComment;\n\tpreviousStatus: string;\n\tnewStatus: string;\n\t/** The admin who moderated */\n\tmoderator: { id: string; name: string | null };\n\t/** Identifies whether an administrator or a plugin initiated the transition. */\n\torigin?: { source: \"admin\"; userId: string } | { source: \"plugin\"; pluginId: string };\n}\n\n/**\n * Handler type for comment:beforeCreate hooks.\n * Returns modified event, or false to reject the comment.\n */\nexport type CommentBeforeCreateHandler = (\n\tevent: CommentBeforeCreateEvent,\n\tctx: PluginContext,\n) => Promise<CommentBeforeCreateEvent | false | void>;\n\n/**\n * Handler type for comment:moderate hook (exclusive provider).\n */\nexport type CommentModerateHandler = (\n\tevent: CommentModerateEvent,\n\tctx: PluginContext,\n) => Promise<ModerationDecision>;\n\n/**\n * Handler type for comment:afterCreate hooks (fire-and-forget).\n */\nexport type CommentAfterCreateHandler = (\n\tevent: CommentAfterCreateEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n/**\n * Handler type for comment:afterModerate hooks (fire-and-forget).\n */\nexport type CommentAfterModerateHandler = (\n\tevent: CommentAfterModerateEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\n// =============================================================================\n// Hook Types\n// =============================================================================\n\n/**\n * Hook configuration\n */\nexport interface HookConfig<THandler> {\n\t/** Explicit ordering - lower numbers run first (default: 100) */\n\tpriority?: number;\n\t/** Max execution time in ms (default: 5000) */\n\ttimeout?: number;\n\t/** Run after these plugins */\n\tdependencies?: string[];\n\t/** Error handling policy */\n\terrorPolicy?: \"continue\" | \"abort\";\n\t/**\n\t * Mark this hook as exclusive — only one plugin can be the active provider.\n\t * Exclusive hooks skip the priority pipeline and dispatch only to the\n\t * admin-selected provider. Used for email:deliver, search, image optimization, etc.\n\t */\n\texclusive?: boolean;\n\t/** The hook handler */\n\thandler: THandler;\n}\n\n/**\n * Acting user that triggered a content hook. Present for authenticated\n * saves; absent for unauthenticated or internal writes.\n */\nexport interface ActorInfo {\n\treadonly id: string;\n\treadonly role: number;\n\treadonly source?: \"api\" | \"mcp\" | \"visual-editor\";\n}\n\nexport type ContentActionOrigin =\n\t| { source: \"api\" | \"mcp\" | \"visual-editor\" }\n\t| { source: \"plugin\"; pluginId: string }\n\t| { source: \"scheduler\" }\n\t| { source: \"system\" };\n\nexport type ContentPolicyDecision = void | { cancel: true; reason: string };\n\n/**\n * Content hook event\n */\nexport interface ContentHookEvent {\n\tcontent: Record<string, unknown>;\n\tcollection: string;\n\tisNew: boolean;\n\t/**\n\t * ID of the existing item on `content:beforeSave` for an update. Absent on\n\t * creates, where the ID is assigned when the save completes, and on\n\t * `content:afterSave`, where `content.id` carries it.\n\t */\n\tid?: string;\n\t/**\n\t * The acting user for this save. Carries the same authenticated identity\n\t * used to set the revision author, so plugins (e.g. audit logs) can record\n\t * who made the change.\n\t */\n\tactor?: ActorInfo;\n}\n\n/**\n * Content delete hook event\n */\nexport interface ContentDeleteEvent {\n\tid: string;\n\tcollection: string;\n\t/** `true` when the content is permanently deleted (not just trashed). */\n\tpermanent: boolean;\n}\n\n/**\n * Content state-change hook event (fired after publish, unpublish, restore,\n * schedule, or unschedule).\n */\nexport interface ContentStateChangeEvent {\n\tcontent: Record<string, unknown>;\n\tcollection: string;\n}\n\n/**\n * Content publish/unpublish hook event.\n */\nexport type ContentPublishStateChangeEvent = ContentStateChangeEvent;\n\n/**\n * Content restore hook event.\n */\nexport type ContentRestoreStateChangeEvent = ContentStateChangeEvent;\n\n/**\n * Content schedule/unschedule hook event.\n */\nexport type ContentScheduleStateChangeEvent = ContentStateChangeEvent;\n\nexport interface ContentPolicyEvent extends ContentStateChangeEvent {\n\torigin: ContentActionOrigin;\n\tactor?: ActorInfo;\n}\n\nexport interface ContentSchedulePolicyEvent extends ContentPolicyEvent {\n\tscheduledAt: string;\n}\n\n/**\n * Media hook event\n */\nexport interface MediaUploadEvent {\n\tfile: { name: string; type: string; size: number };\n}\n\n/**\n * Media after upload event\n */\nexport interface MediaAfterUploadEvent {\n\tmedia: MediaItem;\n}\n\n/**\n * Lifecycle hook event\n */\nexport interface LifecycleEvent {\n\t// Empty for install/activate/deactivate\n}\n\n/**\n * Uninstall hook event\n */\nexport interface UninstallEvent {\n\tdeleteData: boolean;\n}\n\n// Hook handler types - all receive (event, ctx) with unified context\nexport type ContentBeforeSaveHandler = (\n\tevent: ContentHookEvent,\n\tctx: PluginContext,\n) => Promise<Record<string, unknown> | void>;\n\nexport type ContentAfterSaveHandler = (\n\tevent: ContentHookEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentBeforeDeleteHandler = (\n\tevent: ContentDeleteEvent,\n\tctx: PluginContext,\n) => Promise<boolean | void>;\n\nexport type ContentAfterDeleteHandler = (\n\tevent: ContentDeleteEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentBeforePublishHandler = (\n\tevent: ContentPolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentBeforeScheduleHandler = (\n\tevent: ContentSchedulePolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentBeforeUnpublishHandler = (\n\tevent: ContentPolicyEvent,\n\tctx: PluginContext,\n) => Promise<ContentPolicyDecision>;\n\nexport type ContentAfterPublishHandler = (\n\tevent: ContentPublishStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterUnpublishHandler = (\n\tevent: ContentPublishStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterRestoreHandler = (\n\tevent: ContentRestoreStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterScheduleHandler = (\n\tevent: ContentScheduleStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type ContentAfterUnscheduleHandler = (\n\tevent: ContentScheduleStateChangeEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type MediaBeforeUploadHandler = (\n\tevent: MediaUploadEvent,\n\tctx: PluginContext,\n) => Promise<{ name: string; type: string; size: number } | void>;\n\nexport type MediaAfterUploadHandler = (\n\tevent: MediaAfterUploadEvent,\n\tctx: PluginContext,\n) => Promise<void>;\n\nexport type LifecycleHandler = (event: LifecycleEvent, ctx: PluginContext) => Promise<void>;\n\nexport type UninstallHandler = (event: UninstallEvent, ctx: PluginContext) => Promise<void>;\n\n// =============================================================================\n// Public Page Contribution Types\n// =============================================================================\n\n/** Placement targets for page fragment contributions */\nexport type PagePlacement = \"head\" | \"body:start\" | \"body:end\";\n\n/**\n * A single breadcrumb trail item. Used by `PublicPageContext.breadcrumbs`\n * so themes can publish breadcrumb trails that SEO plugins consume.\n */\nexport interface BreadcrumbItem {\n\t/** Display name for this crumb (e.g. \"Home\", \"Blog\", \"My Post\"). */\n\tname: string;\n\t/** Absolute or root-relative URL for this crumb. */\n\turl: string;\n}\n\n/**\n * Describes the page being rendered. Passed to page hooks so plugins\n * can decide what to contribute without fetching content themselves.\n */\nexport interface PublicPageContext {\n\turl: string;\n\tpath: string;\n\tlocale: string | null;\n\tkind: \"content\" | \"custom\";\n\tpageType: string;\n\t/** Full document title for the rendered page */\n\ttitle: string | null;\n\t/** Page-only title for OG/Twitter/JSON-LD headline output */\n\tpageTitle?: string | null;\n\tdescription: string | null;\n\tcanonical: string | null;\n\timage: string | null;\n\tcontent?: {\n\t\tcollection: string;\n\t\tid: string;\n\t\tslug: string | null;\n\t};\n\t/** SEO meta for base metadata generation in EmDashHead */\n\tseo?: {\n\t\togTitle?: string | null;\n\t\togDescription?: string | null;\n\t\togImage?: string | null;\n\t\trobots?: string | null;\n\t};\n\t/** Article metadata for Open Graph article: tags */\n\tarticleMeta?: {\n\t\tpublishedTime?: string | null;\n\t\tmodifiedTime?: string | null;\n\t\tauthor?: string | null;\n\t};\n\t/** Site name for structured data and og:site_name */\n\tsiteName?: string;\n\t/**\n\t * Optional breadcrumb trail for this page, root first. When set,\n\t * SEO plugins should use this verbatim rather than deriving a trail\n\t * from `path`. Themes typically populate this at the point they\n\t * build the context (e.g. from a content hierarchy walk, taxonomy\n\t * lookup, or per-`pageType` routing logic).\n\t *\n\t * Semantics for consumers:\n\t * - `undefined` — theme has no opinion; consumer falls back to\n\t * its own derivation.\n\t * - `[]` — this page has no breadcrumbs (e.g. homepage); consumer\n\t * should skip `BreadcrumbList` emission entirely.\n\t * - Non-empty array — used verbatim for `BreadcrumbList` output.\n\t */\n\tbreadcrumbs?: BreadcrumbItem[];\n\t/** Public-facing site URL (origin) for structured data */\n\tsiteUrl?: string;\n}\n\n// ── page:metadata ───────────────────────────────────────────────\n\nexport interface PageMetadataEvent {\n\tpage: PublicPageContext;\n}\n\n/**\n * Allowed rel values for link contributions.\n * This is a security-critical allowlist -- sandboxed plugins can only inject\n * link tags with these rel values. Adding \"stylesheet\", \"prefetch\", \"prerender\"\n * etc. would allow sandboxed plugins to inject external resources.\n */\nexport type PageMetadataLinkRel =\n\t| \"canonical\"\n\t| \"alternate\"\n\t| \"author\"\n\t| \"license\"\n\t| \"nlweb\"\n\t| \"site.standard.document\";\n\nexport type PageMetadataContribution =\n\t| { kind: \"meta\"; name: string; content: string; key?: string }\n\t| { kind: \"property\"; property: string; content: string; key?: string }\n\t| { kind: \"link\"; rel: PageMetadataLinkRel; href: string; hreflang?: string; key?: string }\n\t| {\n\t\t\tkind: \"jsonld\";\n\t\t\tid?: string;\n\t\t\tgraph: Record<string, unknown> | Array<Record<string, unknown>>;\n\t };\n\nexport type PageMetadataHandler = (\n\tevent: PageMetadataEvent,\n\tctx: PluginContext,\n) =>\n\t| PageMetadataContribution\n\t| PageMetadataContribution[]\n\t| null\n\t| Promise<PageMetadataContribution | PageMetadataContribution[] | null>;\n\n// ── page:fragments (trusted-only) ──────────────────────────────\n\nexport interface PageFragmentEvent {\n\tpage: PublicPageContext;\n}\n\nexport type PageFragmentContribution =\n\t| {\n\t\t\tkind: \"external-script\";\n\t\t\tplacement: PagePlacement;\n\t\t\tsrc: string;\n\t\t\tasync?: boolean;\n\t\t\tdefer?: boolean;\n\t\t\tattributes?: Record<string, string>;\n\t\t\tkey?: string;\n\t }\n\t| {\n\t\t\tkind: \"inline-script\";\n\t\t\tplacement: PagePlacement;\n\t\t\tcode: string;\n\t\t\tattributes?: Record<string, string>;\n\t\t\tkey?: string;\n\t }\n\t| {\n\t\t\tkind: \"html\";\n\t\t\tplacement: PagePlacement;\n\t\t\thtml: string;\n\t\t\tkey?: string;\n\t };\n\nexport type PageFragmentHandler = (\n\tevent: PageFragmentEvent,\n\tctx: PluginContext,\n) =>\n\t| PageFragmentContribution\n\t| PageFragmentContribution[]\n\t| null\n\t| Promise<PageFragmentContribution | PageFragmentContribution[] | null>;\n\n/**\n * Plugin hooks definition\n */\nexport interface PluginHooks {\n\t// Lifecycle hooks\n\t\"plugin:install\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:activate\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:deactivate\"?: HookConfig<LifecycleHandler> | LifecycleHandler;\n\t\"plugin:uninstall\"?: HookConfig<UninstallHandler> | UninstallHandler;\n\n\t// Content hooks\n\t\"content:beforeSave\"?: HookConfig<ContentBeforeSaveHandler> | ContentBeforeSaveHandler;\n\t\"content:afterSave\"?: HookConfig<ContentAfterSaveHandler> | ContentAfterSaveHandler;\n\t\"content:beforeDelete\"?: HookConfig<ContentBeforeDeleteHandler> | ContentBeforeDeleteHandler;\n\t\"content:afterDelete\"?: HookConfig<ContentAfterDeleteHandler> | ContentAfterDeleteHandler;\n\t\"content:beforePublish\"?: HookConfig<ContentBeforePublishHandler> | ContentBeforePublishHandler;\n\t\"content:beforeSchedule\"?:\n\t\t| HookConfig<ContentBeforeScheduleHandler>\n\t\t| ContentBeforeScheduleHandler;\n\t\"content:beforeUnpublish\"?:\n\t\t| HookConfig<ContentBeforeUnpublishHandler>\n\t\t| ContentBeforeUnpublishHandler;\n\t\"content:afterPublish\"?: HookConfig<ContentAfterPublishHandler> | ContentAfterPublishHandler;\n\t\"content:afterUnpublish\"?:\n\t\t| HookConfig<ContentAfterUnpublishHandler>\n\t\t| ContentAfterUnpublishHandler;\n\t\"content:afterRestore\"?: HookConfig<ContentAfterRestoreHandler> | ContentAfterRestoreHandler;\n\t\"content:afterSchedule\"?: HookConfig<ContentAfterScheduleHandler> | ContentAfterScheduleHandler;\n\t\"content:afterUnschedule\"?:\n\t\t| HookConfig<ContentAfterUnscheduleHandler>\n\t\t| ContentAfterUnscheduleHandler;\n\n\t// Media hooks\n\t\"media:beforeUpload\"?: HookConfig<MediaBeforeUploadHandler> | MediaBeforeUploadHandler;\n\t\"media:afterUpload\"?: HookConfig<MediaAfterUploadHandler> | MediaAfterUploadHandler;\n\n\t// Cron hook\n\tcron?: HookConfig<CronHandler> | CronHandler;\n\n\t// Email hooks\n\t\"email:beforeSend\"?: HookConfig<EmailBeforeSendHandler> | EmailBeforeSendHandler;\n\t\"email:deliver\"?: HookConfig<EmailDeliverHandler> | EmailDeliverHandler;\n\t\"email:afterSend\"?: HookConfig<EmailAfterSendHandler> | EmailAfterSendHandler;\n\n\t// Comment hooks\n\t\"comment:beforeCreate\"?: HookConfig<CommentBeforeCreateHandler> | CommentBeforeCreateHandler;\n\t\"comment:moderate\"?: HookConfig<CommentModerateHandler> | CommentModerateHandler;\n\t\"comment:afterCreate\"?: HookConfig<CommentAfterCreateHandler> | CommentAfterCreateHandler;\n\t\"comment:afterModerate\"?: HookConfig<CommentAfterModerateHandler> | CommentAfterModerateHandler;\n\n\t// Public page hooks\n\t\"page:metadata\"?: HookConfig<PageMetadataHandler> | PageMetadataHandler;\n\t\"page:fragments\"?: HookConfig<PageFragmentHandler> | PageFragmentHandler;\n}\n\n/**\n * Hook names\n */\n/**\n * Hook name in a manifest. Core's exhaustive union of recognised hook names,\n * derived from the `PluginHooks` registry. The serialised manifest carries\n * these as opaque strings; this stricter type is only used for type-checking\n * inside core. `ManifestHookEntry` is re-exported from\n * `@emdash-cms/plugin-types` near the top of this file.\n */\nexport type HookName = keyof PluginHooks;\n\n/**\n * Resolved hook with normalized config\n */\nexport interface ResolvedHook<THandler> {\n\tpriority: number;\n\ttimeout: number;\n\tdependencies: string[];\n\terrorPolicy: \"continue\" | \"abort\";\n\t/** Whether this hook is exclusive (provider pattern) */\n\texclusive: boolean;\n\thandler: THandler;\n\tpluginId: string;\n}\n\n// =============================================================================\n// Request Metadata Types\n// =============================================================================\n\n/**\n * Geographic location information derived from the request.\n * Available when running on Cloudflare Workers (via the `cf` object).\n */\nexport interface GeoInfo {\n\tcountry: string | null;\n\tregion: string | null;\n\tcity: string | null;\n}\n\n/**\n * Normalized request metadata available to plugin route handlers.\n * Extracted from request headers and platform-specific properties.\n */\nexport interface RequestMeta {\n\tip: string | null;\n\tuserAgent: string | null;\n\treferer: string | null;\n\tgeo: GeoInfo | null;\n}\n\n// =============================================================================\n// Route Types\n// =============================================================================\n\n/**\n * Route handler context extends plugin context with request-specific data\n */\nexport interface RouteContext<TInput = unknown> extends PluginContext {\n\t/** Validated input from request body */\n\tinput: TInput;\n\t/** Original request */\n\trequest: Request;\n\t/** Normalized request metadata (IP, user agent, geo) */\n\trequestMeta: RequestMeta;\n\t/** Host-attested context for a validated Block Kit request. */\n\tui?: PluginUiContext;\n\t/**\n\t * Authenticated caller, if the route is private. The host has already\n\t * authenticated and authorized this user before dispatch, so the value\n\t * is trustworthy — unlike a user id read from the request body.\n\t *\n\t * `undefined` for public routes (which skip auth entirely) and for\n\t * token-authed requests where no user is bound to the token.\n\t *\n\t * Not gated by the `users:read` capability: this is the caller's own\n\t * identity for the current request, not a user directory lookup.\n\t */\n\tuser?: UserInfo;\n}\n\n/**\n * Route definition\n */\nexport interface PluginRoute<TInput = unknown> extends Omit<RouteOptions, \"request\"> {\n\t/** Zod schema for input validation */\n\tinput?: z.ZodType<TInput>;\n\t/**\n\t * Mark this route as publicly accessible (no authentication required).\n\t * Public routes skip session/token auth and CSRF checks.\n\t */\n\tpublic?: boolean;\n\t/** RBAC permission required to invoke the route. Legacy routes default to plugins:manage. */\n\tpermission?: Permission;\n\t/**\n\t * `Cache-Control` header value for successful GET responses, e.g.\n\t * `\"public, max-age=60, stale-while-revalidate=300\"`. Only honored on\n\t * routes that are also `public: true` — authenticated responses always\n\t * keep the default `private, no-store`. Errors are never cached.\n\t */\n\tcacheControl?: string;\n\t/** Bounded request parsing and incoming-header declaration. */\n\trequest?: PluginRouteRequest;\n\t/** Route handler */\n\thandler: { bivarianceHack(ctx: RouteContext<TInput>): Promise<unknown> }[\"bivarianceHack\"];\n}\n\nexport type PluginRouteInput<TMode extends PluginRouteBodyMode> = TMode extends \"none\"\n\t? PluginRouteQuery\n\t: TMode extends \"text\"\n\t\t? string\n\t\t: TMode extends \"bytes\"\n\t\t\t? Uint8Array\n\t\t\t: TMode extends \"form-data\"\n\t\t\t\t? PluginFormData\n\t\t\t\t: unknown;\n\nexport type PluginRouteDefinition<TMode extends PluginRouteBodyMode = PluginRouteBodyMode> = Omit<\n\tPluginRoute<PluginRouteInput<TMode>>,\n\t\"request\"\n> & {\n\trequest: PluginRouteRequest & { body: TMode };\n};\n\nexport interface PluginMcpToolDefinition {\n\tdescription: string;\n\troute: string;\n\tinput: z.ZodType;\n\toutput?: z.ZodType;\n\tdestructive?: boolean;\n}\n\nexport interface PluginMcpConfig {\n\ttools: Record<string, PluginMcpToolDefinition>;\n}\n\n// =============================================================================\n// Plugin Definition\n// =============================================================================\n\n/**\n * Admin page definition\n */\nexport interface PluginAdminPage {\n\tpath: string;\n\tlabel: string;\n\ticon?: string;\n}\n\n/**\n * Dashboard widget definition\n */\nexport interface PluginDashboardWidget {\n\tid: string;\n\tsize?: \"full\" | \"half\" | \"third\";\n\ttitle?: string;\n}\n\nexport interface PluginEditorPanel {\n\tid: string;\n\ttitle: string;\n\troute: string;\n\tcollections?: string[];\n\torder?: number;\n\tdraft?: PluginEditorDraftAccess;\n}\n\nexport interface PluginEditorAction {\n\tid: string;\n\tlabel: string;\n\troute: string;\n\tplacement: \"toolbar\" | \"overflow\";\n\tcollections?: string[];\n\tstyle?: \"default\" | \"danger\";\n\tconfirm?: ConfirmDialog;\n\tdraft?: PluginEditorDraftAccess;\n}\n\n/**\n * Settings field types (for admin UI generation)\n */\nexport type SettingFieldType =\n\t| \"string\"\n\t| \"number\"\n\t| \"boolean\"\n\t| \"select\"\n\t| \"secret\"\n\t| \"url\"\n\t| \"email\";\n\nexport interface BaseSettingField {\n\ttype: SettingFieldType;\n\tlabel: string;\n\tdescription?: string;\n}\n\nexport interface StringSettingField extends BaseSettingField {\n\ttype: \"string\";\n\tdefault?: string;\n\tmultiline?: boolean;\n}\n\nexport interface NumberSettingField extends BaseSettingField {\n\ttype: \"number\";\n\tdefault?: number;\n\tmin?: number;\n\tmax?: number;\n}\n\nexport interface BooleanSettingField extends BaseSettingField {\n\ttype: \"boolean\";\n\tdefault?: boolean;\n}\n\nexport interface SelectSettingField extends BaseSettingField {\n\ttype: \"select\";\n\toptions: Array<{ value: string; label: string }>;\n\tdefault?: string;\n}\n\nexport interface SecretSettingField extends BaseSettingField {\n\ttype: \"secret\";\n}\n\nexport interface UrlSettingField extends BaseSettingField {\n\ttype: \"url\";\n\tdefault?: string;\n\tplaceholder?: string;\n}\n\nexport interface EmailSettingField extends BaseSettingField {\n\ttype: \"email\";\n\tdefault?: string;\n\tplaceholder?: string;\n}\n\nexport type SettingField =\n\t| StringSettingField\n\t| NumberSettingField\n\t| BooleanSettingField\n\t| SelectSettingField\n\t| SecretSettingField\n\t| UrlSettingField\n\t| EmailSettingField;\n\n/**\n * Block Kit element for block editing fields.\n * This is the `Element` discriminated union from `@emdash-cms/blocks`.\n * Plugin authors should use `@emdash-cms/blocks` builder functions to create these.\n */\nexport type PortableTextBlockField = Element;\n\n/**\n * Configuration for a Portable Text block type contributed by a plugin\n */\nexport interface PortableTextBlockConfig {\n\t/** Block type name (must match the `_type` in Portable Text) */\n\ttype: string;\n\t/** Human-readable label shown in slash commands and modals */\n\tlabel: string;\n\t/** Icon key (e.g., \"video\", \"code\", \"link\", \"link-external\") */\n\ticon?: string;\n\t/** Description shown in slash command menu */\n\tdescription?: string;\n\t/** Placeholder text for the URL input */\n\tplaceholder?: string;\n\t/** Block Kit form fields for the editing UI. If declared, replaces the simple URL input. */\n\tfields?: PortableTextBlockField[];\n\t/**\n\t * Optional. Display category in the slash menu. Defaults to \"Embeds\".\n\t *\n\t * Plugin authors should pick a meaningful category that reflects what the\n\t * block actually is — e.g. \"Sections\", \"Marketing\", \"Media\", \"Embeds\",\n\t * \"Layout\". Blocks with the same category are grouped together in the\n\t * editor's slash menu.\n\t */\n\tcategory?: string;\n}\n\n/**\n * Configuration for a field widget type contributed by a plugin.\n * A field widget provides a custom editing UI for a schema field.\n * The field references the widget via `widget: \"pluginId:widgetName\"`.\n */\nexport interface FieldWidgetConfig {\n\t/** Widget name (without plugin ID prefix) */\n\tname: string;\n\t/** Human-readable label for the admin UI */\n\tlabel: string;\n\t/** Which field types this widget can edit (e.g., [\"json\", \"string\"]) */\n\tfieldTypes: FieldType[];\n\t/** Block Kit elements for sandboxed rendering. Omit for trusted plugins using React. */\n\telements?: Element[];\n}\n\n/**\n * Admin configuration\n */\nexport interface PluginAdminConfig {\n\t/** Module specifier for admin UI exports (e.g., \"@emdash-cms/plugin-audit-log/admin\") */\n\tentry?: string;\n\t/** Settings schema for auto-generated UI */\n\tsettingsSchema?: Record<string, SettingField>;\n\t/** Admin pages */\n\tpages?: PluginAdminPage[];\n\t/** Dashboard widgets */\n\twidgets?: PluginDashboardWidget[];\n\t/** Saved-entry Block Kit panels. */\n\teditorPanels?: PluginEditorPanel[];\n\t/** Saved-entry host-rendered actions. */\n\teditorActions?: PluginEditorAction[];\n\t/** Portable Text block types this plugin provides */\n\tportableTextBlocks?: PortableTextBlockConfig[];\n\t/** Field widget types this plugin provides */\n\tfieldWidgets?: FieldWidgetConfig[];\n}\n\n/**\n * Plugin definition - input to definePlugin()\n */\nexport interface PluginDefinition<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\t/** Unique plugin identifier */\n\tid: string;\n\t/** Plugin version (semver) */\n\tversion: string;\n\n\t/** Declared capabilities */\n\tcapabilities?: PluginCapability[];\n\n\t/** Allowed hosts for network:request (wildcards supported: *.example.com) */\n\tallowedHosts?: string[];\n\n\t/** Storage collections with indexes */\n\tstorage?: TStorage;\n\n\t/** Hooks */\n\thooks?: PluginHooks;\n\n\t/** API routes */\n\troutes?: Record<string, PluginRoute>;\n\n\t/** Routes explicitly exposed as agent-callable MCP tools. */\n\tmcp?: PluginMcpConfig;\n\n\t/** Admin UI configuration */\n\tadmin?: PluginAdminConfig;\n}\n\n/**\n * Resolved plugin - after definePlugin() processing\n */\nexport interface ResolvedPlugin<TStorage extends PluginStorageConfig = PluginStorageConfig> {\n\tid: string;\n\tversion: string;\n\tcapabilities: PluginCapability[];\n\tallowedHosts: string[];\n\tstorage: TStorage;\n\thooks: ResolvedPluginHooks;\n\troutes: Record<string, PluginRoute>;\n\tmcp?: PluginMcpConfig;\n\tadmin: PluginAdminConfig;\n}\n\n/**\n * Resolved hooks with normalized config\n */\nexport interface ResolvedPluginHooks {\n\t\"plugin:install\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:activate\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:deactivate\"?: ResolvedHook<LifecycleHandler>;\n\t\"plugin:uninstall\"?: ResolvedHook<UninstallHandler>;\n\t\"content:beforeSave\"?: ResolvedHook<ContentBeforeSaveHandler>;\n\t\"content:afterSave\"?: ResolvedHook<ContentAfterSaveHandler>;\n\t\"content:beforeDelete\"?: ResolvedHook<ContentBeforeDeleteHandler>;\n\t\"content:afterDelete\"?: ResolvedHook<ContentAfterDeleteHandler>;\n\t\"content:beforePublish\"?: ResolvedHook<ContentBeforePublishHandler>;\n\t\"content:beforeSchedule\"?: ResolvedHook<ContentBeforeScheduleHandler>;\n\t\"content:beforeUnpublish\"?: ResolvedHook<ContentBeforeUnpublishHandler>;\n\t\"content:afterPublish\"?: ResolvedHook<ContentAfterPublishHandler>;\n\t\"content:afterUnpublish\"?: ResolvedHook<ContentAfterUnpublishHandler>;\n\t\"content:afterRestore\"?: ResolvedHook<ContentAfterRestoreHandler>;\n\t\"content:afterSchedule\"?: ResolvedHook<ContentAfterScheduleHandler>;\n\t\"content:afterUnschedule\"?: ResolvedHook<ContentAfterUnscheduleHandler>;\n\t\"media:beforeUpload\"?: ResolvedHook<MediaBeforeUploadHandler>;\n\t\"media:afterUpload\"?: ResolvedHook<MediaAfterUploadHandler>;\n\tcron?: ResolvedHook<CronHandler>;\n\t\"email:beforeSend\"?: ResolvedHook<EmailBeforeSendHandler>;\n\t\"email:deliver\"?: ResolvedHook<EmailDeliverHandler>;\n\t\"email:afterSend\"?: ResolvedHook<EmailAfterSendHandler>;\n\t\"comment:beforeCreate\"?: ResolvedHook<CommentBeforeCreateHandler>;\n\t\"comment:moderate\"?: ResolvedHook<CommentModerateHandler>;\n\t\"comment:afterCreate\"?: ResolvedHook<CommentAfterCreateHandler>;\n\t\"comment:afterModerate\"?: ResolvedHook<CommentAfterModerateHandler>;\n\t\"page:metadata\"?: ResolvedHook<PageMetadataHandler>;\n\t\"page:fragments\"?: ResolvedHook<PageFragmentHandler>;\n}\n\n// =============================================================================\n// Plugin Admin Exports\n// =============================================================================\n\n/**\n * What a plugin exports from its /admin entrypoint\n * Uses generic component type to avoid React dependency\n */\nexport interface PluginAdminExports {\n\twidgets?: Record<string, JSX.Element>;\n\tpages?: Record<string, JSX.Element>;\n\tfields?: Record<string, JSX.Element>;\n}\n\n// =============================================================================\n// Sandbox Types\n// =============================================================================\n\n/**\n * Plugin manifest — the metadata portion of a plugin bundle, used for\n * sandboxed plugins loaded from the marketplace.\n *\n * This interface is core's stricter version of the manifest contract: it\n * uses the exhaustive `HookName` union and core's typed `PluginAdminConfig`.\n * The wire-shape lives in `@emdash-cms/plugin-types` as `PluginManifest`\n * with looser types (so the registry CLI can serialise hook names it\n * doesn't know about). Both must stay structurally compatible: every value\n * of this type must be assignable to the shared one. The static assertion\n * below catches any drift at compile time.\n */\nexport interface PluginManifest {\n\tid: string;\n\tversion: string;\n\t/**\n\t * The trust contract (see `@emdash-cms/plugin-types`). Authoritative;\n\t * `capabilities`/`allowedHosts` are derived from it at the parse boundary\n\t * via `reconcileManifestAccess`. Optional during the wire-format migration.\n\t */\n\tdeclaredAccess?: DeclaredAccess;\n\tcapabilities: PluginCapability[];\n\tallowedHosts: string[];\n\tstorage: PluginStorageConfig;\n\t/** Hook declarations — either plain name strings or structured objects */\n\thooks: Array<ManifestHookEntry | HookName>;\n\t/** Route declarations — either plain name strings or structured objects */\n\troutes: Array<ManifestRouteEntry | string>;\n\tmcp?: PluginMcpManifestConfig;\n\tadmin: PluginAdminConfig;\n}\n\n// Type-level guard: core's `PluginManifest` is intentionally a SUBTYPE of\n// the shared wire shape (`@emdash-cms/plugin-types` `PluginManifest`). The\n// wire shape uses looser types like `string` for hook names so the registry\n// CLI can serialise plugins targeting hook versions this core doesn't yet\n// know about. Core narrows `string` to `HookName` and `Record<string,\n// unknown>` to `PluginAdminConfig` because core's loader actually executes\n// against those types.\n//\n// We assert one direction at compile time: `core extends shared`. The\n// reverse direction (`shared extends core`) intentionally does NOT hold\n// because shared is wider -- a manifest written against the wire shape\n// could carry a hook name core doesn't know. That runtime narrowing is the\n// job of `manifest-schema.ts` (zod-validated, called at every JSON.parse\n// of a manifest.json), not of the type system. The static check below\n// catches the OTHER failure mode: core adding a required field or\n// non-assignable type that the wire shape doesn't allow.\n//\n// `type X = never` is itself legal as a type alias, so the assertion has to\n// be in a value position (`const _check: T = true`) for the compiler to\n// error when T resolves to `never`. Don't replace this with a bare type\n// alias.\ntype _AssertManifestCompat =\n\tPluginManifest extends import(\"@emdash-cms/plugin-types\").PluginManifest ? true : never;\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst _MANIFEST_COMPAT: _AssertManifestCompat = true;\n"],"mappings":";;;AAmFA,MAAa,iCAET;CACH,CAAC,iBAAiB,eAAe;CACjC,CAAC,0BAA0B,eAAe;CAC1C,CAAC,oBAAoB,kBAAkB;CACvC,CAAC,mBAAmB,eAAe;CACnC,CAAC,eAAe,aAAa;CAC7B,CAAC,qBAAqB,gBAAgB;CACtC,CAAC,mBAAmB,iBAAiB;CACrC,CAAC,gCAAgC,kBAAkB;CACnD;AAMD,SAAgB,4BAA4B,cAA2C;CACtF,MAAM,aAAa,IAAI,IAAI,sBAAsB,aAAa,CAAC;AAC/D,MAAK,MAAM,CAAC,SAAS,YAAY,+BAChC,KAAI,WAAW,IAAI,QAAQ,CAAE,YAAW,IAAI,QAAQ;AAErD,QAAO,CAAC,GAAG,WAAW"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/media/upload-attempts.ts
|
|
2
|
+
async function removeUploadAttempt(storage, repo, storageKey, options = {}) {
|
|
3
|
+
try {
|
|
4
|
+
if (!await repo.claimUploadAttemptForCleanup(storageKey)) {
|
|
5
|
+
if (await repo.hasUploadAttempt(storageKey) || !options.allowUntracked) return false;
|
|
6
|
+
}
|
|
7
|
+
} catch (error) {
|
|
8
|
+
console.error("[media] upload cleanup claim failed:", error);
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
await storage.delete(storageKey);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error("[media] upload cleanup failed:", error);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
await repo.deleteUploadAttempt(storageKey);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("[media] upload cleanup record deletion failed:", error);
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { removeUploadAttempt as t };
|
|
27
|
+
//# sourceMappingURL=upload-attempts-2xdnoKGe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-attempts-2xdnoKGe.mjs","names":[],"sources":["../src/media/upload-attempts.ts"],"sourcesContent":["import type { MediaRepository } from \"../database/repositories/media.js\";\nimport type { Storage } from \"../storage/types.js\";\n\nexport async function removeUploadAttempt(\n\tstorage: Storage,\n\trepo: MediaRepository,\n\tstorageKey: string,\n\toptions: { allowUntracked?: boolean } = {},\n): Promise<boolean> {\n\ttry {\n\t\tif (!(await repo.claimUploadAttemptForCleanup(storageKey))) {\n\t\t\tconst tracked = await repo.hasUploadAttempt(storageKey);\n\t\t\tif (tracked || !options.allowUntracked) return false;\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(\"[media] upload cleanup claim failed:\", error);\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait storage.delete(storageKey);\n\t} catch (error) {\n\t\tconsole.error(\"[media] upload cleanup failed:\", error);\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait repo.deleteUploadAttempt(storageKey);\n\t} catch (error) {\n\t\tconsole.error(\"[media] upload cleanup record deletion failed:\", error);\n\t}\n\treturn true;\n}\n"],"mappings":";AAGA,eAAsB,oBACrB,SACA,MACA,YACA,UAAwC,EAAE,EACvB;AACnB,KAAI;AACH,MAAI,CAAE,MAAM,KAAK,6BAA6B,WAAW,EAExD;OADgB,MAAM,KAAK,iBAAiB,WAAW,IACxC,CAAC,QAAQ,eAAgB,QAAO;;UAExC,OAAO;AACf,UAAQ,MAAM,wCAAwC,MAAM;AAC5D,SAAO;;AAGR,KAAI;AACH,QAAM,QAAQ,OAAO,WAAW;UACxB,OAAO;AACf,UAAQ,MAAM,kCAAkC,MAAM;AACtD,SAAO;;AAGR,KAAI;AACH,QAAM,KAAK,oBAAoB,WAAW;UAClC,OAAO;AACf,UAAQ,MAAM,kDAAkD,MAAM;;AAEvE,QAAO"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/schema/url-pattern.ts
|
|
2
|
+
const URL_PARAM_PATTERN = /\{(\w+)\}/g;
|
|
3
|
+
const REGEX_SPECIAL_CHARACTERS = /[.*+?^${}()|[\]\\]/g;
|
|
4
|
+
const INVALID_LITERAL_PATTERN = /[{}]/;
|
|
5
|
+
function escapeRegex(literal) {
|
|
6
|
+
return literal.replace(REGEX_SPECIAL_CHARACTERS, "\\$&");
|
|
7
|
+
}
|
|
8
|
+
function compileUrlPattern(pattern) {
|
|
9
|
+
const paramNames = [];
|
|
10
|
+
let regexSource = "";
|
|
11
|
+
let previousIndex = 0;
|
|
12
|
+
for (const match of pattern.matchAll(URL_PARAM_PATTERN)) {
|
|
13
|
+
const matchIndex = match.index;
|
|
14
|
+
const literal = pattern.slice(previousIndex, matchIndex);
|
|
15
|
+
if (INVALID_LITERAL_PATTERN.test(literal)) throw new Error("Invalid URL pattern placeholder");
|
|
16
|
+
regexSource += escapeRegex(literal);
|
|
17
|
+
const name = match[1];
|
|
18
|
+
paramNames.push(name);
|
|
19
|
+
regexSource += "([^/]+)";
|
|
20
|
+
previousIndex = matchIndex + match[0].length;
|
|
21
|
+
}
|
|
22
|
+
const trailingLiteral = pattern.slice(previousIndex);
|
|
23
|
+
if (INVALID_LITERAL_PATTERN.test(trailingLiteral)) throw new Error("Invalid URL pattern placeholder");
|
|
24
|
+
regexSource += escapeRegex(trailingLiteral);
|
|
25
|
+
return {
|
|
26
|
+
regex: new RegExp(`^${regexSource}$`),
|
|
27
|
+
paramNames
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { compileUrlPattern as t };
|
|
33
|
+
//# sourceMappingURL=url-pattern-3m3reMzr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-pattern-3m3reMzr.mjs","names":[],"sources":["../src/schema/url-pattern.ts"],"sourcesContent":["const URL_PARAM_PATTERN = /\\{(\\w+)\\}/g;\nconst REGEX_SPECIAL_CHARACTERS = /[.*+?^${}()|[\\]\\\\]/g;\nconst INVALID_LITERAL_PATTERN = /[{}]/;\n\nfunction escapeRegex(literal: string): string {\n\treturn literal.replace(REGEX_SPECIAL_CHARACTERS, \"\\\\$&\");\n}\n\nexport function compileUrlPattern(pattern: string): { regex: RegExp; paramNames: string[] } {\n\tconst paramNames: string[] = [];\n\tlet regexSource = \"\";\n\tlet previousIndex = 0;\n\n\tfor (const match of pattern.matchAll(URL_PARAM_PATTERN)) {\n\t\tconst matchIndex = match.index;\n\t\tconst literal = pattern.slice(previousIndex, matchIndex);\n\t\tif (INVALID_LITERAL_PATTERN.test(literal)) throw new Error(\"Invalid URL pattern placeholder\");\n\t\tregexSource += escapeRegex(literal);\n\n\t\tconst name = match[1];\n\t\tparamNames.push(name);\n\t\tregexSource += \"([^/]+)\";\n\t\tpreviousIndex = matchIndex + match[0].length;\n\t}\n\n\tconst trailingLiteral = pattern.slice(previousIndex);\n\tif (INVALID_LITERAL_PATTERN.test(trailingLiteral)) {\n\t\tthrow new Error(\"Invalid URL pattern placeholder\");\n\t}\n\tregexSource += escapeRegex(trailingLiteral);\n\n\treturn { regex: new RegExp(`^${regexSource}$`), paramNames };\n}\n"],"mappings":";AAAA,MAAM,oBAAoB;AAC1B,MAAM,2BAA2B;AACjC,MAAM,0BAA0B;AAEhC,SAAS,YAAY,SAAyB;AAC7C,QAAO,QAAQ,QAAQ,0BAA0B,OAAO;;AAGzD,SAAgB,kBAAkB,SAA0D;CAC3F,MAAM,aAAuB,EAAE;CAC/B,IAAI,cAAc;CAClB,IAAI,gBAAgB;AAEpB,MAAK,MAAM,SAAS,QAAQ,SAAS,kBAAkB,EAAE;EACxD,MAAM,aAAa,MAAM;EACzB,MAAM,UAAU,QAAQ,MAAM,eAAe,WAAW;AACxD,MAAI,wBAAwB,KAAK,QAAQ,CAAE,OAAM,IAAI,MAAM,kCAAkC;AAC7F,iBAAe,YAAY,QAAQ;EAEnC,MAAM,OAAO,MAAM;AACnB,aAAW,KAAK,KAAK;AACrB,iBAAe;AACf,kBAAgB,aAAa,MAAM,GAAG;;CAGvC,MAAM,kBAAkB,QAAQ,MAAM,cAAc;AACpD,KAAI,wBAAwB,KAAK,gBAAgB,CAChD,OAAM,IAAI,MAAM,kCAAkC;AAEnD,gBAAe,YAAY,gBAAgB;AAE3C,QAAO;EAAE,OAAO,IAAI,OAAO,IAAI,YAAY,GAAG;EAAE;EAAY"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-BmWyou79.mjs";
|
|
2
|
+
import { o as decodeCursor, s as encodeCursor } from "./types-BkUg2yHx.mjs";
|
|
3
|
+
import { ulid } from "ulidx";
|
|
4
|
+
|
|
5
|
+
//#region src/database/repositories/user.ts
|
|
6
|
+
/**
|
|
7
|
+
* User repository for CRUD operations
|
|
8
|
+
*/
|
|
9
|
+
var UserRepository = class UserRepository {
|
|
10
|
+
constructor(db) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a new user
|
|
15
|
+
*/
|
|
16
|
+
async create(input) {
|
|
17
|
+
const id = ulid();
|
|
18
|
+
const row = {
|
|
19
|
+
id,
|
|
20
|
+
email: input.email.toLowerCase(),
|
|
21
|
+
name: input.name ?? null,
|
|
22
|
+
role: UserRepository.resolveRole(input.role ?? 10),
|
|
23
|
+
avatar_url: input.avatarUrl ?? null,
|
|
24
|
+
email_verified: 0,
|
|
25
|
+
data: input.data ? JSON.stringify(input.data) : null
|
|
26
|
+
};
|
|
27
|
+
await this.db.insertInto("users").values(row).execute();
|
|
28
|
+
const user = await this.findById(id);
|
|
29
|
+
if (!user) throw new Error("Failed to create user");
|
|
30
|
+
return user;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Find user by ID
|
|
34
|
+
*/
|
|
35
|
+
async findById(id) {
|
|
36
|
+
const row = await this.db.selectFrom("users").selectAll().where("id", "=", id).executeTakeFirst();
|
|
37
|
+
return row ? this.rowToUser(row) : null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Batch-resolve users by ID. Returns only the users that exist; missing
|
|
41
|
+
* IDs are silently dropped. Chunked at `SQL_BATCH_SIZE` to stay within
|
|
42
|
+
* D1's bind-parameter limit.
|
|
43
|
+
*/
|
|
44
|
+
async findByIds(ids) {
|
|
45
|
+
const unique = [...new Set(ids)].filter((id) => id.length > 0);
|
|
46
|
+
if (unique.length === 0) return [];
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const batch of chunks(unique, SQL_BATCH_SIZE)) {
|
|
49
|
+
const rows = await this.db.selectFrom("users").selectAll().where("id", "in", batch).execute();
|
|
50
|
+
for (const row of rows) out.push(this.rowToUser(row));
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Find user by email (case-insensitive)
|
|
56
|
+
*/
|
|
57
|
+
async findByEmail(email) {
|
|
58
|
+
const row = await this.db.selectFrom("users").selectAll().where("email", "=", email.toLowerCase()).executeTakeFirst();
|
|
59
|
+
return row ? this.rowToUser(row) : null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* List all users with cursor-based pagination
|
|
63
|
+
*/
|
|
64
|
+
async findMany(options = {}) {
|
|
65
|
+
const limit = Math.min(Math.max(1, options.limit || 50), 100);
|
|
66
|
+
let query = this.db.selectFrom("users").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
|
|
67
|
+
if (options.role !== void 0) query = query.where("role", "=", UserRepository.resolveRole(options.role));
|
|
68
|
+
if (options.cursor) {
|
|
69
|
+
const decoded = decodeCursor(options.cursor);
|
|
70
|
+
query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
|
|
71
|
+
}
|
|
72
|
+
const rows = await query.execute();
|
|
73
|
+
const items = rows.slice(0, limit).map((row) => this.rowToUser(row));
|
|
74
|
+
const result = { items };
|
|
75
|
+
if (rows.length > limit && items.length > 0) {
|
|
76
|
+
const last = items.at(-1);
|
|
77
|
+
result.nextCursor = encodeCursor(last.createdAt, last.id);
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Update a user
|
|
83
|
+
*/
|
|
84
|
+
async update(id, input) {
|
|
85
|
+
if (!await this.findById(id)) return null;
|
|
86
|
+
const updates = {};
|
|
87
|
+
if (input.name !== void 0) updates.name = input.name;
|
|
88
|
+
if (input.role !== void 0) updates.role = UserRepository.resolveRole(input.role);
|
|
89
|
+
if (input.avatarUrl !== void 0) updates.avatar_url = input.avatarUrl;
|
|
90
|
+
if (input.data !== void 0) updates.data = JSON.stringify(input.data);
|
|
91
|
+
if (Object.keys(updates).length > 0) await this.db.updateTable("users").set(updates).where("id", "=", id).execute();
|
|
92
|
+
return this.findById(id);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Delete a user
|
|
96
|
+
*/
|
|
97
|
+
async delete(id) {
|
|
98
|
+
return ((await this.db.deleteFrom("users").where("id", "=", id).executeTakeFirst()).numDeletedRows ?? 0) > 0;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Count users
|
|
102
|
+
*/
|
|
103
|
+
async count(role) {
|
|
104
|
+
let query = this.db.selectFrom("users").select((eb) => eb.fn.count("id").as("count"));
|
|
105
|
+
if (role !== void 0) query = query.where("role", "=", UserRepository.resolveRole(role));
|
|
106
|
+
const result = await query.executeTakeFirst();
|
|
107
|
+
return Number(result?.count || 0);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if email exists
|
|
111
|
+
*/
|
|
112
|
+
async emailExists(email) {
|
|
113
|
+
return !!await this.db.selectFrom("users").select("id").where("email", "=", email.toLowerCase()).executeTakeFirst();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convert database row to User object
|
|
117
|
+
*/
|
|
118
|
+
rowToUser(row) {
|
|
119
|
+
return {
|
|
120
|
+
id: row.id,
|
|
121
|
+
email: row.email,
|
|
122
|
+
name: row.name,
|
|
123
|
+
role: UserRepository.toRole(row.role),
|
|
124
|
+
avatarUrl: row.avatar_url,
|
|
125
|
+
emailVerified: row.email_verified === 1,
|
|
126
|
+
data: row.data ? JSON.parse(row.data) : null,
|
|
127
|
+
createdAt: row.created_at
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Map of role name strings to numeric levels */
|
|
131
|
+
static ROLE_NAME_TO_LEVEL = {
|
|
132
|
+
subscriber: 10,
|
|
133
|
+
contributor: 20,
|
|
134
|
+
author: 30,
|
|
135
|
+
editor: 40,
|
|
136
|
+
admin: 50
|
|
137
|
+
};
|
|
138
|
+
/** Valid numeric role levels */
|
|
139
|
+
static VALID_LEVELS = new Set([
|
|
140
|
+
10,
|
|
141
|
+
20,
|
|
142
|
+
30,
|
|
143
|
+
40,
|
|
144
|
+
50
|
|
145
|
+
]);
|
|
146
|
+
/**
|
|
147
|
+
* Resolve a role name or number to a valid numeric UserRole.
|
|
148
|
+
* Accepts both string names ("admin") and numeric levels (50).
|
|
149
|
+
*/
|
|
150
|
+
static resolveRole(role) {
|
|
151
|
+
if (typeof role === "string") {
|
|
152
|
+
const level = UserRepository.ROLE_NAME_TO_LEVEL[role];
|
|
153
|
+
if (level === void 0) throw new Error(`Invalid role name: ${role}`);
|
|
154
|
+
return level;
|
|
155
|
+
}
|
|
156
|
+
if (!UserRepository.VALID_LEVELS.has(role)) throw new Error(`Invalid role level: ${role}`);
|
|
157
|
+
return role;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Convert a raw DB integer to a typed UserRole.
|
|
161
|
+
* Falls back to subscriber (10) for unknown values.
|
|
162
|
+
*/
|
|
163
|
+
static toRole(level) {
|
|
164
|
+
if (UserRepository.VALID_LEVELS.has(level)) return level;
|
|
165
|
+
return 10;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { UserRepository as t };
|
|
171
|
+
//# sourceMappingURL=user-DroRntkx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-DroRntkx.mjs","names":[],"sources":["../src/database/repositories/user.ts"],"sourcesContent":["import type { Kysely, Selectable, Updateable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport type { Database, UserTable } from \"../types.js\";\nimport { encodeCursor, decodeCursor, type FindManyResult } from \"./types.js\";\n\ntype UserRow = Selectable<UserTable>;\n\n/**\n * Valid role levels matching the database schema.\n * 10=subscriber, 20=contributor, 30=author, 40=editor, 50=admin\n */\nexport type UserRole = 10 | 20 | 30 | 40 | 50;\n\n/** String role names for convenience APIs */\nexport type UserRoleName = \"subscriber\" | \"contributor\" | \"author\" | \"editor\" | \"admin\";\n\nexport interface User {\n\tid: string;\n\temail: string;\n\tname: string | null;\n\trole: UserRole;\n\tavatarUrl: string | null;\n\temailVerified: boolean;\n\tdata: Record<string, unknown> | null;\n\tcreatedAt: string;\n}\n\nexport interface CreateUserInput {\n\temail: string;\n\tname?: string;\n\trole?: UserRole | UserRoleName;\n\tavatarUrl?: string;\n\tdata?: Record<string, unknown>;\n}\n\nexport interface UpdateUserInput {\n\tname?: string;\n\trole?: UserRole | UserRoleName;\n\tavatarUrl?: string | null;\n\tdata?: Record<string, unknown>;\n}\n\n/**\n * User repository for CRUD operations\n */\nexport class UserRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new user\n\t */\n\tasync create(input: CreateUserInput): Promise<User> {\n\t\tconst id = ulid();\n\n\t\tconst row: Omit<UserTable, \"created_at\" | \"updated_at\" | \"disabled\"> = {\n\t\t\tid,\n\t\t\temail: input.email.toLowerCase(),\n\t\t\tname: input.name ?? null,\n\t\t\trole: UserRepository.resolveRole(input.role ?? 10),\n\t\t\tavatar_url: input.avatarUrl ?? null,\n\t\t\temail_verified: 0,\n\t\t\tdata: input.data ? JSON.stringify(input.data) : null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"users\").values(row).execute();\n\n\t\tconst user = await this.findById(id);\n\t\tif (!user) {\n\t\t\tthrow new Error(\"Failed to create user\");\n\t\t}\n\t\treturn user;\n\t}\n\n\t/**\n\t * Find user by ID\n\t */\n\tasync findById(id: string): Promise<User | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToUser(row) : null;\n\t}\n\n\t/**\n\t * Batch-resolve users by ID. Returns only the users that exist; missing\n\t * IDs are silently dropped. Chunked at `SQL_BATCH_SIZE` to stay within\n\t * D1's bind-parameter limit.\n\t */\n\tasync findByIds(ids: string[]): Promise<User[]> {\n\t\tconst unique = [...new Set(ids)].filter((id) => id.length > 0);\n\t\tif (unique.length === 0) return [];\n\n\t\tconst out: User[] = [];\n\t\tfor (const batch of chunks(unique, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db.selectFrom(\"users\").selectAll().where(\"id\", \"in\", batch).execute();\n\t\t\tfor (const row of rows) out.push(this.rowToUser(row));\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Find user by email (case-insensitive)\n\t */\n\tasync findByEmail(email: string): Promise<User | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.selectAll()\n\t\t\t.where(\"email\", \"=\", email.toLowerCase())\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToUser(row) : null;\n\t}\n\n\t/**\n\t * List all users with cursor-based pagination\n\t */\n\tasync findMany(\n\t\toptions: {\n\t\t\trole?: UserRole | UserRoleName;\n\t\t\tlimit?: number;\n\t\t\tcursor?: string;\n\t\t} = {},\n\t): Promise<FindManyResult<User>> {\n\t\tconst limit = Math.min(Math.max(1, options.limit || 50), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tif (options.role !== undefined) {\n\t\t\tquery = query.where(\"role\", \"=\", UserRepository.resolveRole(options.role));\n\t\t}\n\n\t\tif (options.cursor) {\n\t\t\tconst decoded = decodeCursor(options.cursor);\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"created_at\", \"<\", decoded.orderValue),\n\t\t\t\t\teb.and([eb(\"created_at\", \"=\", decoded.orderValue), eb(\"id\", \"<\", decoded.id)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst items = rows.slice(0, limit).map((row) => this.rowToUser(row));\n\t\tconst result: FindManyResult<User> = { items };\n\n\t\tif (rows.length > limit && items.length > 0) {\n\t\t\tconst last = items.at(-1)!;\n\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Update a user\n\t */\n\tasync update(id: string, input: UpdateUserInput): Promise<User | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst updates: Updateable<UserTable> = {};\n\t\tif (input.name !== undefined) updates.name = input.name;\n\t\tif (input.role !== undefined) updates.role = UserRepository.resolveRole(input.role);\n\t\tif (input.avatarUrl !== undefined) updates.avatar_url = input.avatarUrl;\n\t\tif (input.data !== undefined) updates.data = JSON.stringify(input.data);\n\n\t\tif (Object.keys(updates).length > 0) {\n\t\t\tawait this.db.updateTable(\"users\").set(updates).where(\"id\", \"=\", id).execute();\n\t\t}\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Delete a user\n\t */\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst result = await this.db.deleteFrom(\"users\").where(\"id\", \"=\", id).executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n\n\t/**\n\t * Count users\n\t */\n\tasync count(role?: UserRole | UserRoleName): Promise<number> {\n\t\tlet query = this.db.selectFrom(\"users\").select((eb) => eb.fn.count(\"id\").as(\"count\"));\n\n\t\tif (role !== undefined) {\n\t\t\tquery = query.where(\"role\", \"=\", UserRepository.resolveRole(role));\n\t\t}\n\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t/**\n\t * Check if email exists\n\t */\n\tasync emailExists(email: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"email\", \"=\", email.toLowerCase())\n\t\t\t.executeTakeFirst();\n\n\t\treturn !!row;\n\t}\n\n\t/**\n\t * Convert database row to User object\n\t */\n\tprivate rowToUser(row: UserRow): User {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\temail: row.email,\n\t\t\tname: row.name,\n\t\t\trole: UserRepository.toRole(row.role),\n\t\t\tavatarUrl: row.avatar_url,\n\t\t\temailVerified: row.email_verified === 1,\n\t\t\tdata: row.data ? JSON.parse(row.data) : null,\n\t\t\tcreatedAt: row.created_at,\n\t\t};\n\t}\n\n\t/** Map of role name strings to numeric levels */\n\tprivate static readonly ROLE_NAME_TO_LEVEL: Record<UserRoleName, UserRole> = {\n\t\tsubscriber: 10,\n\t\tcontributor: 20,\n\t\tauthor: 30,\n\t\teditor: 40,\n\t\tadmin: 50,\n\t};\n\n\t/** Valid numeric role levels */\n\tprivate static readonly VALID_LEVELS = new Set<number>([10, 20, 30, 40, 50]);\n\n\t/**\n\t * Resolve a role name or number to a valid numeric UserRole.\n\t * Accepts both string names (\"admin\") and numeric levels (50).\n\t */\n\tstatic resolveRole(role: UserRole | UserRoleName): UserRole {\n\t\tif (typeof role === \"string\") {\n\t\t\tconst level = UserRepository.ROLE_NAME_TO_LEVEL[role];\n\t\t\tif (level === undefined) {\n\t\t\t\tthrow new Error(`Invalid role name: ${role}`);\n\t\t\t}\n\t\t\treturn level;\n\t\t}\n\t\tif (!UserRepository.VALID_LEVELS.has(role)) {\n\t\t\tthrow new Error(`Invalid role level: ${role}`);\n\t\t}\n\t\treturn role;\n\t}\n\n\t/**\n\t * Convert a raw DB integer to a typed UserRole.\n\t * Falls back to subscriber (10) for unknown values.\n\t */\n\tprivate static toRole(level: number): UserRole {\n\t\tif (UserRepository.VALID_LEVELS.has(level)) return level as UserRole;\n\t\treturn 10;\n\t}\n}\n"],"mappings":";;;;;;;;AA+CA,IAAa,iBAAb,MAAa,eAAe;CAC3B,YAAY,AAAQ,IAAsB;EAAtB;;;;;CAKpB,MAAM,OAAO,OAAuC;EACnD,MAAM,KAAK,MAAM;EAEjB,MAAM,MAAiE;GACtE;GACA,OAAO,MAAM,MAAM,aAAa;GAChC,MAAM,MAAM,QAAQ;GACpB,MAAM,eAAe,YAAY,MAAM,QAAQ,GAAG;GAClD,YAAY,MAAM,aAAa;GAC/B,gBAAgB;GAChB,MAAM,MAAM,OAAO,KAAK,UAAU,MAAM,KAAK,GAAG;GAChD;AAED,QAAM,KAAK,GAAG,WAAW,QAAQ,CAAC,OAAO,IAAI,CAAC,SAAS;EAEvD,MAAM,OAAO,MAAM,KAAK,SAAS,GAAG;AACpC,MAAI,CAAC,KACJ,OAAM,IAAI,MAAM,wBAAwB;AAEzC,SAAO;;;;;CAMR,MAAM,SAAS,IAAkC;EAChD,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,WAAW,CACX,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;;;CAQpC,MAAM,UAAU,KAAgC;EAC/C,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,QAAQ,OAAO,GAAG,SAAS,EAAE;AAC9D,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE;EAElC,MAAM,MAAc,EAAE;AACtB,OAAK,MAAM,SAAS,OAAO,QAAQ,eAAe,EAAE;GACnD,MAAM,OAAO,MAAM,KAAK,GAAG,WAAW,QAAQ,CAAC,WAAW,CAAC,MAAM,MAAM,MAAM,MAAM,CAAC,SAAS;AAC7F,QAAK,MAAM,OAAO,KAAM,KAAI,KAAK,KAAK,UAAU,IAAI,CAAC;;AAEtD,SAAO;;;;;CAMR,MAAM,YAAY,OAAqC;EACtD,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,WAAW,CACX,MAAM,SAAS,KAAK,MAAM,aAAa,CAAC,CACxC,kBAAkB;AAEpB,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;CAMpC,MAAM,SACL,UAII,EAAE,EAC0B;EAChC,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,GAAG,QAAQ,SAAS,GAAG,EAAE,IAAI;EAE7D,IAAI,QAAQ,KAAK,GACf,WAAW,QAAQ,CACnB,WAAW,CACX,QAAQ,cAAc,OAAO,CAC7B,QAAQ,MAAM,OAAO,CACrB,MAAM,QAAQ,EAAE;AAElB,MAAI,QAAQ,SAAS,OACpB,SAAQ,MAAM,MAAM,QAAQ,KAAK,eAAe,YAAY,QAAQ,KAAK,CAAC;AAG3E,MAAI,QAAQ,QAAQ;GACnB,MAAM,UAAU,aAAa,QAAQ,OAAO;AAC5C,WAAQ,MAAM,OAAO,OACpB,GAAG,GAAG,CACL,GAAG,cAAc,KAAK,QAAQ,WAAW,EACzC,GAAG,IAAI,CAAC,GAAG,cAAc,KAAK,QAAQ,WAAW,EAAE,GAAG,MAAM,KAAK,QAAQ,GAAG,CAAC,CAAC,CAC9E,CAAC,CACF;;EAGF,MAAM,OAAO,MAAM,MAAM,SAAS;EAClC,MAAM,QAAQ,KAAK,MAAM,GAAG,MAAM,CAAC,KAAK,QAAQ,KAAK,UAAU,IAAI,CAAC;EACpE,MAAM,SAA+B,EAAE,OAAO;AAE9C,MAAI,KAAK,SAAS,SAAS,MAAM,SAAS,GAAG;GAC5C,MAAM,OAAO,MAAM,GAAG,GAAG;AACzB,UAAO,aAAa,aAAa,KAAK,WAAW,KAAK,GAAG;;AAG1D,SAAO;;;;;CAMR,MAAM,OAAO,IAAY,OAA8C;AAEtE,MAAI,CADa,MAAM,KAAK,SAAS,GAAG,CACzB,QAAO;EAEtB,MAAM,UAAiC,EAAE;AACzC,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AACnD,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,eAAe,YAAY,MAAM,KAAK;AACnF,MAAI,MAAM,cAAc,OAAW,SAAQ,aAAa,MAAM;AAC9D,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,KAAK,UAAU,MAAM,KAAK;AAEvE,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EACjC,OAAM,KAAK,GAAG,YAAY,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,MAAM,KAAK,GAAG,CAAC,SAAS;AAG/E,SAAO,KAAK,SAAS,GAAG;;;;;CAMzB,MAAM,OAAO,IAA8B;AAG1C,WAFe,MAAM,KAAK,GAAG,WAAW,QAAQ,CAAC,MAAM,MAAM,KAAK,GAAG,CAAC,kBAAkB,EAEzE,kBAAkB,KAAK;;;;;CAMvC,MAAM,MAAM,MAAiD;EAC5D,IAAI,QAAQ,KAAK,GAAG,WAAW,QAAQ,CAAC,QAAQ,OAAO,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC;AAErF,MAAI,SAAS,OACZ,SAAQ,MAAM,MAAM,QAAQ,KAAK,eAAe,YAAY,KAAK,CAAC;EAGnE,MAAM,SAAS,MAAM,MAAM,kBAAkB;AAC7C,SAAO,OAAO,QAAQ,SAAS,EAAE;;;;;CAMlC,MAAM,YAAY,OAAiC;AAOlD,SAAO,CAAC,CANI,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,OAAO,KAAK,CACZ,MAAM,SAAS,KAAK,MAAM,aAAa,CAAC,CACxC,kBAAkB;;;;;CAQrB,AAAQ,UAAU,KAAoB;AACrC,SAAO;GACN,IAAI,IAAI;GACR,OAAO,IAAI;GACX,MAAM,IAAI;GACV,MAAM,eAAe,OAAO,IAAI,KAAK;GACrC,WAAW,IAAI;GACf,eAAe,IAAI,mBAAmB;GACtC,MAAM,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK,GAAG;GACxC,WAAW,IAAI;GACf;;;CAIF,OAAwB,qBAAqD;EAC5E,YAAY;EACZ,aAAa;EACb,QAAQ;EACR,QAAQ;EACR,OAAO;EACP;;CAGD,OAAwB,eAAe,IAAI,IAAY;EAAC;EAAI;EAAI;EAAI;EAAI;EAAG,CAAC;;;;;CAM5E,OAAO,YAAY,MAAyC;AAC3D,MAAI,OAAO,SAAS,UAAU;GAC7B,MAAM,QAAQ,eAAe,mBAAmB;AAChD,OAAI,UAAU,OACb,OAAM,IAAI,MAAM,sBAAsB,OAAO;AAE9C,UAAO;;AAER,MAAI,CAAC,eAAe,aAAa,IAAI,KAAK,CACzC,OAAM,IAAI,MAAM,uBAAuB,OAAO;AAE/C,SAAO;;;;;;CAOR,OAAe,OAAO,OAAyB;AAC9C,MAAI,eAAe,aAAa,IAAI,MAAM,CAAE,QAAO;AACnD,SAAO"}
|