emdash 0.40.0 → 0.41.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-CbKDcPJi.mjs +26 -0
- package/dist/action-token-CbKDcPJi.mjs.map +1 -0
- package/dist/activation-PtniBLt9.mjs +382 -0
- package/dist/activation-PtniBLt9.mjs.map +1 -0
- package/dist/adapters-C_Tf5x90.d.mts +171 -0
- package/dist/adapters-C_Tf5x90.d.mts.map +1 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs +116 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +4 -4
- package/dist/api/route-utils.mjs +46 -45
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +10 -10
- package/dist/api-CXwQkV_m.mjs +5122 -0
- package/dist/api-CXwQkV_m.mjs.map +1 -0
- package/dist/api-tokens-89WlohEN.mjs +166 -0
- package/dist/api-tokens-89WlohEN.mjs.map +1 -0
- package/dist/apply-Do3KNnUk.mjs +1659 -0
- package/dist/apply-Do3KNnUk.mjs.map +1 -0
- package/dist/approvals-CAX9Yw33.mjs +460 -0
- package/dist/approvals-CAX9Yw33.mjs.map +1 -0
- package/dist/artifact-fetch-B9W4CEST.mjs +659 -0
- package/dist/artifact-fetch-B9W4CEST.mjs.map +1 -0
- package/dist/astro/index.d.mts +14 -14
- package/dist/astro/index.mjs +26 -30
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +12 -12
- package/dist/astro/middleware/auth.mjs +10 -10
- package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +7 -7
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +12 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +110 -106
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +14 -14
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +14 -14
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/index.mjs +23 -23
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -18
- package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/bulk.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/counts.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/index.mjs +17 -17
- 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 +20 -20
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +25 -25
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +31 -31
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +82 -78
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +81 -77
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +83 -79
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -9
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +74 -70
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -67
- 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 +5 -5
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/transfer/_...path_.mjs +4 -4
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/capabilities.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +4 -4
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +15 -15
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +6 -6
- package/dist/astro/routes/api/admin/users/index.mjs +14 -14
- package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/accept.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/invite/index.mjs +16 -16
- package/dist/astro/routes/api/auth/invite/register-options.mjs +17 -17
- package/dist/astro/routes/api/auth/logout.mjs +5 -5
- package/dist/astro/routes/api/auth/magic-link/send.mjs +18 -18
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +14 -14
- package/dist/astro/routes/api/auth/me.mjs +15 -15
- package/dist/astro/routes/api/auth/mode.mjs +5 -5
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +14 -14
- package/dist/astro/routes/api/auth/passkey/index.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/options.mjs +19 -19
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +17 -17
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/passkey/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/request.mjs +17 -17
- package/dist/astro/routes/api/auth/signup/verify.mjs +4 -4
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +31 -31
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts +1 -2
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +42 -53
- 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 +34 -29
- 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 +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +25 -24
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/index.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/trash.mjs +15 -15
- package/dist/astro/routes/api/dashboard.mjs +10 -9
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +5 -5
- package/dist/astro/routes/api/health.mjs +6 -6
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -12
- package/dist/astro/routes/api/import/wordpress/media.mjs +19 -19
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +18 -18
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +28 -28
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +34 -34
- package/dist/astro/routes/api/manifest.mjs +6 -6
- package/dist/astro/routes/api/mcp.mjs +98 -118
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +19 -19
- package/dist/astro/routes/api/media/_id_/replace.mjs +16 -16
- package/dist/astro/routes/api/media/_id_/upload.mjs +9 -9
- package/dist/astro/routes/api/media/_id_/usage.mjs +33 -33
- package/dist/astro/routes/api/media/_id_.mjs +31 -31
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +9 -9
- package/dist/astro/routes/api/media/folders/_id_.mjs +16 -16
- package/dist/astro/routes/api/media/folders/index.mjs +16 -16
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +5 -5
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +5 -5
- package/dist/astro/routes/api/media/providers/index.mjs +5 -5
- package/dist/astro/routes/api/media/upload-url.mjs +18 -18
- package/dist/astro/routes/api/media.mjs +35 -35
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/items.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/translations.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_.mjs +17 -17
- package/dist/astro/routes/api/menus/index.mjs +17 -17
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.d.mts +2 -1
- package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -1
- package/dist/astro/routes/api/oauth/device/authorize.mjs +23 -9
- package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/device/code.mjs +11 -11
- package/dist/astro/routes/api/oauth/device/token.mjs +10 -10
- package/dist/astro/routes/api/oauth/register.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/refresh.mjs +8 -8
- package/dist/astro/routes/api/oauth/token/revoke.mjs +8 -8
- package/dist/astro/routes/api/oauth/token.mjs +8 -8
- package/dist/astro/routes/api/openapi.json.mjs +20 -20
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +11 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs +19 -19
- package/dist/astro/routes/api/redirects/404s/summary.mjs +19 -19
- package/dist/astro/routes/api/redirects/_id_.mjs +19 -19
- package/dist/astro/routes/api/redirects/index.mjs +19 -19
- package/dist/astro/routes/api/relations/_id_/index.mjs +34 -29
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +36 -31
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +5 -5
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -69
- 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 +71 -67
- 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 +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +16 -16
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +19 -19
- package/dist/astro/routes/api/search/index.mjs +18 -18
- package/dist/astro/routes/api/search/rebuild.mjs +19 -19
- package/dist/astro/routes/api/search/stats.mjs +9 -9
- package/dist/astro/routes/api/search/suggest.mjs +18 -18
- package/dist/astro/routes/api/sections/_slug_.mjs +18 -18
- package/dist/astro/routes/api/sections/index.mjs +18 -18
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/export.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +6 -6
- package/dist/astro/routes/api/settings.mjs +21 -21
- package/dist/astro/routes/api/setup/admin-verify.mjs +19 -19
- package/dist/astro/routes/api/setup/admin.mjs +18 -18
- package/dist/astro/routes/api/setup/dev-bypass.mjs +45 -39
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/index.mjs +80 -49
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +6 -6
- package/dist/astro/routes/api/snapshot.mjs +9 -9
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -22
- package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +36 -35
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +23 -23
- package/dist/astro/routes/api/themes/preview.mjs +6 -6
- package/dist/astro/routes/api/typegen.mjs +8 -8
- package/dist/astro/routes/api/visual-editing/action-token.mjs +6 -6
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +19 -19
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- 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 +16 -16
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/index.mjs +19 -19
- package/dist/astro/routes/api/widget-components.mjs +5 -5
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +28 -18
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/audit-CrgmE9LE.mjs +127 -0
- package/dist/audit-CrgmE9LE.mjs.map +1 -0
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/authoritative-records-C2YzIdbu.mjs +5172 -0
- package/dist/authoritative-records-C2YzIdbu.mjs.map +1 -0
- package/dist/authorize-WgdKF8QY.mjs +49 -0
- package/dist/authorize-WgdKF8QY.mjs.map +1 -0
- package/dist/backup-Ck8_lMO3.mjs +246 -0
- package/dist/backup-Ck8_lMO3.mjs.map +1 -0
- package/dist/block-types-BQ90asVI.mjs +132 -0
- package/dist/block-types-BQ90asVI.mjs.map +1 -0
- package/dist/block-values-ACFqgB1D.mjs +175 -0
- package/dist/block-values-ACFqgB1D.mjs.map +1 -0
- package/dist/bundle-Db1iNMv_.mjs +667 -0
- package/dist/bundle-Db1iNMv_.mjs.map +1 -0
- package/dist/byline-BayaYGoj.mjs +909 -0
- package/dist/byline-BayaYGoj.mjs.map +1 -0
- package/dist/byline-fields-B8HH-35f.mjs +254 -0
- package/dist/byline-fields-B8HH-35f.mjs.map +1 -0
- package/dist/byline-fields-hMPjf6Eu.mjs +123 -0
- package/dist/byline-fields-hMPjf6Eu.mjs.map +1 -0
- package/dist/byline-registry-B_EK_TQf.mjs +406 -0
- package/dist/byline-registry-B_EK_TQf.mjs.map +1 -0
- package/dist/bylines-DFAaFXWi.mjs +214 -0
- package/dist/bylines-DFAaFXWi.mjs.map +1 -0
- package/dist/bylines-DkIxUxmr.mjs +232 -0
- package/dist/bylines-DkIxUxmr.mjs.map +1 -0
- package/dist/cache-DkvhQ8XE.mjs +108 -0
- package/dist/cache-DkvhQ8XE.mjs.map +1 -0
- package/dist/canonical-CcSuuTlH.mjs +174 -0
- package/dist/canonical-CcSuuTlH.mjs.map +1 -0
- package/dist/capture-triggers-DJEoOTOq.mjs +362 -0
- package/dist/capture-triggers-DJEoOTOq.mjs.map +1 -0
- package/dist/challenge-store-CvBl81AQ.mjs +51 -0
- package/dist/challenge-store-CvBl81AQ.mjs.map +1 -0
- package/dist/checksum-CClweQzI.mjs +162 -0
- package/dist/checksum-CClweQzI.mjs.map +1 -0
- package/dist/chrome-tags-D5caJwwp.mjs +24 -0
- package/dist/chrome-tags-D5caJwwp.mjs.map +1 -0
- package/dist/chunks-DwBaj8aT.mjs +25 -0
- package/dist/chunks-DwBaj8aT.mjs.map +1 -0
- package/dist/cli/index.mjs +374 -761
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +18 -18
- package/dist/client/index.mjs +2 -2
- package/dist/collection-deletion-CLCdXsnV.mjs +436 -0
- package/dist/collection-deletion-CLCdXsnV.mjs.map +1 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs +217 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs.map +1 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs +85 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs.map +1 -0
- package/dist/comment-D2uvL63j.mjs +313 -0
- package/dist/comment-D2uvL63j.mjs.map +1 -0
- package/dist/comment-reaction-DevUuzg4.mjs +85 -0
- package/dist/comment-reaction-DevUuzg4.mjs.map +1 -0
- package/dist/comments-Cq0s7_hO.mjs +195 -0
- package/dist/comments-Cq0s7_hO.mjs.map +1 -0
- package/dist/comments-M4EDYAHw.mjs +99 -0
- package/dist/comments-M4EDYAHw.mjs.map +1 -0
- package/dist/components-CuIGwXMs.mjs +108 -0
- package/dist/components-CuIGwXMs.mjs.map +1 -0
- package/dist/config-52Ea5IWt.d.mts +39 -0
- package/dist/config-52Ea5IWt.d.mts.map +1 -0
- package/dist/config-CCz3xOLc.mjs +242 -0
- package/dist/config-CCz3xOLc.mjs.map +1 -0
- package/dist/config-D3d5Qudq.d.mts +6669 -0
- package/dist/config-D3d5Qudq.d.mts.map +1 -0
- package/dist/content-CbnufDsM.mjs +2018 -0
- package/dist/content-CbnufDsM.mjs.map +1 -0
- package/dist/content-list-query-D_7B1FE5.d.mts +26 -0
- package/dist/content-list-query-D_7B1FE5.d.mts.map +1 -0
- package/dist/content-policy-CYu6K1KB.mjs +46 -0
- package/dist/content-policy-CYu6K1KB.mjs.map +1 -0
- package/dist/content-repair-DlDUgFGp.mjs +442 -0
- package/dist/content-repair-DlDUgFGp.mjs.map +1 -0
- package/dist/context-CGQLA1-a.mjs +1922 -0
- package/dist/context-CGQLA1-a.mjs.map +1 -0
- package/dist/cron-c4D5C5Fx.mjs +284 -0
- package/dist/cron-c4D5C5Fx.mjs.map +1 -0
- package/dist/dashboard-CBq9kmOn.mjs +151 -0
- package/dist/dashboard-CBq9kmOn.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/default-DPsys51U.mjs +81 -0
- package/dist/default-DPsys51U.mjs.map +1 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts +9 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts.map +1 -0
- package/dist/dev-typegen-HRxwLRcT.mjs +29 -0
- package/dist/dev-typegen-HRxwLRcT.mjs.map +1 -0
- package/dist/device-flow-OcSqE9uY.mjs +521 -0
- package/dist/device-flow-OcSqE9uY.mjs.map +1 -0
- package/dist/digest-DVZ--cE9.mjs +194 -0
- package/dist/digest-DVZ--cE9.mjs.map +1 -0
- package/dist/direct-executor-DyjAqkpT.mjs +104 -0
- package/dist/direct-executor-DyjAqkpT.mjs.map +1 -0
- package/dist/dist-FPR93_xf.mjs +810 -0
- package/dist/dist-FPR93_xf.mjs.map +1 -0
- package/dist/email-console-DyQIgEnz.mjs +50 -0
- package/dist/email-console-DyQIgEnz.mjs.map +1 -0
- package/dist/email-locale-BYb16rVd.mjs +25 -0
- package/dist/email-locale-BYb16rVd.mjs.map +1 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs +4214 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs.map +1 -0
- package/dist/enrich-DBtCncE2.mjs +194 -0
- package/dist/enrich-DBtCncE2.mjs.map +1 -0
- package/dist/entry-lock-BN5y4YbO.d.mts +4481 -0
- package/dist/entry-lock-BN5y4YbO.d.mts.map +1 -0
- package/dist/entry-lock-BaRBHCsH.mjs +1173 -0
- package/dist/entry-lock-BaRBHCsH.mjs.map +1 -0
- package/dist/entry-lock-C6NcnZPV.mjs +163 -0
- package/dist/entry-lock-C6NcnZPV.mjs.map +1 -0
- package/dist/entry-locks-BTyQLdbC.mjs +167 -0
- package/dist/entry-locks-BTyQLdbC.mjs.map +1 -0
- package/dist/error-BfsNNrIE.mjs +90 -0
- package/dist/error-BfsNNrIE.mjs.map +1 -0
- package/dist/errors-BN1QAnEY.mjs +460 -0
- package/dist/errors-BN1QAnEY.mjs.map +1 -0
- package/dist/errors-Bt3goF8I.mjs +120 -0
- package/dist/errors-Bt3goF8I.mjs.map +1 -0
- package/dist/escape-BveidMa2.mjs +9 -0
- package/dist/escape-BveidMa2.mjs.map +1 -0
- package/dist/fence-Bb_IbCxI.mjs +162 -0
- package/dist/fence-Bb_IbCxI.mjs.map +1 -0
- package/dist/field-defs-cache-CsZctvbu.mjs +77 -0
- package/dist/field-defs-cache-CsZctvbu.mjs.map +1 -0
- package/dist/field-map-6m9rF49t.mjs +83 -0
- package/dist/field-map-6m9rF49t.mjs.map +1 -0
- package/dist/focal-point-CZ3d1wK5.mjs +23 -0
- package/dist/focal-point-CZ3d1wK5.mjs.map +1 -0
- package/dist/fts-manager-CCaZTp8y.mjs +443 -0
- package/dist/fts-manager-CCaZTp8y.mjs.map +1 -0
- package/dist/gc-xowRjczI.mjs +75 -0
- package/dist/gc-xowRjczI.mjs.map +1 -0
- package/dist/hash-COVK27Pc.mjs +37 -0
- package/dist/hash-COVK27Pc.mjs.map +1 -0
- package/dist/hook-result-CYSk0XFe.d.mts +31 -0
- package/dist/hook-result-CYSk0XFe.d.mts.map +1 -0
- package/dist/hreflang-CChPV7jx.mjs +105 -0
- package/dist/hreflang-CChPV7jx.mjs.map +1 -0
- package/dist/hreflang-DRslq3QI.d.mts +50 -0
- package/dist/hreflang-DRslq3QI.d.mts.map +1 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs +339 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs.map +1 -0
- package/dist/identity-NVTOOQyq.mjs +35 -0
- package/dist/identity-NVTOOQyq.mjs.map +1 -0
- package/dist/import-wpSO2N0x.mjs +2020 -0
- package/dist/import-wpSO2N0x.mjs.map +1 -0
- package/dist/index-CDs2wq4X.d.mts +623 -0
- package/dist/index-CDs2wq4X.d.mts.map +1 -0
- package/dist/index.d.mts +24 -24
- package/dist/index.mjs +103 -101
- package/dist/install-finalization-D9R9R-W8.mjs +58 -0
- package/dist/install-finalization-D9R9R-W8.mjs.map +1 -0
- package/dist/keys-Bck6LBfF.mjs +61 -0
- package/dist/keys-Bck6LBfF.mjs.map +1 -0
- package/dist/kinds-CYmRESWj.mjs +974 -0
- package/dist/kinds-CYmRESWj.mjs.map +1 -0
- package/dist/lifecycle-C815ZQfV.mjs +25 -0
- package/dist/lifecycle-C815ZQfV.mjs.map +1 -0
- package/dist/load-D99axixL.mjs +28 -0
- package/dist/load-D99axixL.mjs.map +1 -0
- package/dist/loader-CrRPfkHS.mjs +1197 -0
- package/dist/loader-CrRPfkHS.mjs.map +1 -0
- package/dist/loops-DMKlygqX.mjs +203 -0
- package/dist/loops-DMKlygqX.mjs.map +1 -0
- package/dist/manifest-builder-BQzCHNgB.mjs +189 -0
- package/dist/manifest-builder-BQzCHNgB.mjs.map +1 -0
- package/dist/manifest-schema-Ci2gmd0u.mjs +492 -0
- package/dist/manifest-schema-Ci2gmd0u.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 -14
- package/dist/media/local-runtime.mjs +6 -6
- package/dist/media-BUQePMxP.mjs +373 -0
- package/dist/media-BUQePMxP.mjs.map +1 -0
- package/dist/media-DH8ibNlY.mjs +294 -0
- package/dist/media-DH8ibNlY.mjs.map +1 -0
- package/dist/media-OEIQ3bVc.mjs +408 -0
- package/dist/media-OEIQ3bVc.mjs.map +1 -0
- package/dist/media-allowlist-pYtaBA95.mjs +44 -0
- package/dist/media-allowlist-pYtaBA95.mjs.map +1 -0
- package/dist/media-folders-Bf8_s4de.mjs +210 -0
- package/dist/media-folders-Bf8_s4de.mjs.map +1 -0
- package/dist/media-url-C6klEuNd.mjs +43 -0
- package/dist/media-url-C6klEuNd.mjs.map +1 -0
- package/dist/media-usage-D7Y64m6v.mjs +1629 -0
- package/dist/media-usage-D7Y64m6v.mjs.map +1 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs +78 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs.map +1 -0
- package/dist/media-usage-work-DommYhYA.mjs +152 -0
- package/dist/media-usage-work-DommYhYA.mjs.map +1 -0
- package/dist/media-usage-work-HU63hNDu.mjs +586 -0
- package/dist/media-usage-work-HU63hNDu.mjs.map +1 -0
- package/dist/menus-BQfusWEC.mjs +3608 -0
- package/dist/menus-BQfusWEC.mjs.map +1 -0
- package/dist/menus-BtwjQt5s.mjs +753 -0
- package/dist/menus-BtwjQt5s.mjs.map +1 -0
- package/dist/menus-p_M1V7J_.mjs +139 -0
- package/dist/menus-p_M1V7J_.mjs.map +1 -0
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/mime-C94qBG-P.mjs +36 -0
- package/dist/mime-C94qBG-P.mjs.map +1 -0
- package/dist/mode-DpYW3w6U.mjs +23 -0
- package/dist/mode-DpYW3w6U.mjs.map +1 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs +46 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs.map +1 -0
- package/dist/normalize-DduyxBjf.mjs +191 -0
- package/dist/normalize-DduyxBjf.mjs.map +1 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs +274 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs.map +1 -0
- package/dist/oauth-clients-DENiDQri.mjs +266 -0
- package/dist/oauth-clients-DENiDQri.mjs.map +1 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs +50 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs.map +1 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs +26 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs.map +1 -0
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/options-BYa1FgIM.d.mts +81 -0
- package/dist/options-BYa1FgIM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.mjs +5 -5
- package/dist/parse-CORGGhHf.mjs +81 -0
- package/dist/parse-CORGGhHf.mjs.map +1 -0
- package/dist/parse-avNM1xWV.d.mts +168 -0
- package/dist/parse-avNM1xWV.d.mts.map +1 -0
- package/dist/passkey-config-Dih5YeIS.mjs +46 -0
- package/dist/passkey-config-Dih5YeIS.mjs.map +1 -0
- package/dist/paths-d51RFm8M.mjs +77 -0
- package/dist/paths-d51RFm8M.mjs.map +1 -0
- package/dist/patterns-CoqlXUvk.mjs +145 -0
- package/dist/patterns-CoqlXUvk.mjs.map +1 -0
- package/dist/placeholder-D2aksPMF.d.mts +306 -0
- package/dist/placeholder-D2aksPMF.d.mts.map +1 -0
- package/dist/plan-DqeZKuaR.mjs +135 -0
- package/dist/plan-DqeZKuaR.mjs.map +1 -0
- package/dist/plugin-test-runtime.d.mts +14 -14
- package/dist/plugin-test-runtime.mjs +110 -107
- package/dist/plugin-types.d.mts +2 -2
- package/dist/plugin-utils.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.mjs +3 -3
- package/dist/plugins/host.d.mts +5 -5
- package/dist/plugins/host.mjs +42 -41
- package/dist/plugins-Bb7oqjQA.mjs +277 -0
- package/dist/plugins-Bb7oqjQA.mjs.map +1 -0
- package/dist/policy-BcEqut3n.mjs +45 -0
- package/dist/policy-BcEqut3n.mjs.map +1 -0
- package/dist/portable-text-DXE8ymtD.mjs +307 -0
- package/dist/portable-text-DXE8ymtD.mjs.map +1 -0
- package/dist/preview-DEDWbwA_.mjs +107 -0
- package/dist/preview-DEDWbwA_.mjs.map +1 -0
- package/dist/protocol-BJbTzvwl.d.mts +61 -0
- package/dist/protocol-BJbTzvwl.d.mts.map +1 -0
- package/dist/public-submission-D9c9S14m.mjs +250 -0
- package/dist/public-submission-D9c9S14m.mjs.map +1 -0
- package/dist/public-url-CIRe-2T6.mjs +101 -0
- package/dist/public-url-CIRe-2T6.mjs.map +1 -0
- package/dist/query-BzifXlPS.mjs +1156 -0
- package/dist/query-BzifXlPS.mjs.map +1 -0
- package/dist/query-OzMJ6vJP.mjs +41 -0
- package/dist/query-OzMJ6vJP.mjs.map +1 -0
- package/dist/rate-limit-Csp60Vik.mjs +120 -0
- package/dist/rate-limit-Csp60Vik.mjs.map +1 -0
- package/dist/receipt-B-aU4hpJ.mjs +43 -0
- package/dist/receipt-B-aU4hpJ.mjs.map +1 -0
- package/dist/redirect-CDSw1sU3.mjs +17 -0
- package/dist/redirect-CDSw1sU3.mjs.map +1 -0
- package/dist/redirect-D1ArbO85.mjs +411 -0
- package/dist/redirect-D1ArbO85.mjs.map +1 -0
- package/dist/redirects-BjTwDTsV.mjs +148 -0
- package/dist/redirects-BjTwDTsV.mjs.map +1 -0
- package/dist/redirects-Ck50kH3n.mjs +446 -0
- package/dist/redirects-Ck50kH3n.mjs.map +1 -0
- package/dist/registry/testing.mjs +3 -3
- package/dist/registry-CFcNCayZ.mjs +6754 -0
- package/dist/registry-CFcNCayZ.mjs.map +1 -0
- package/dist/relations-Cfaa1fDl.mjs +776 -0
- package/dist/relations-Cfaa1fDl.mjs.map +1 -0
- package/dist/request-cache-iHRlHx1d.mjs +104 -0
- package/dist/request-cache-iHRlHx1d.mjs.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/request-meta-D47mqyev.mjs +141 -0
- package/dist/request-meta-D47mqyev.mjs.map +1 -0
- package/dist/resolve-BPE8sMvx.mjs +99 -0
- package/dist/resolve-BPE8sMvx.mjs.map +1 -0
- package/dist/resolve-C0s1E_fH.mjs +199 -0
- package/dist/resolve-C0s1E_fH.mjs.map +1 -0
- package/dist/revision-j1p4-bOj.mjs +302 -0
- package/dist/revision-j1p4-bOj.mjs.map +1 -0
- package/dist/route-wire-C9PJV9aL.mjs +197 -0
- package/dist/route-wire-C9PJV9aL.mjs.map +1 -0
- package/dist/routes-lyYw0mMf.mjs +272 -0
- package/dist/routes-lyYw0mMf.mjs.map +1 -0
- package/dist/runner-B3eyB9Gb.mjs +6121 -0
- package/dist/runner-B3eyB9Gb.mjs.map +1 -0
- package/dist/runner-DoYH2Jcu.d.mts +68 -0
- package/dist/runner-DoYH2Jcu.d.mts.map +1 -0
- package/dist/runtime.d.mts +13 -13
- package/dist/runtime.mjs +3 -3
- package/dist/schema-BAayK46S.mjs +13 -0
- package/dist/schema-BAayK46S.mjs.map +1 -0
- package/dist/schema-Gqcl-8G4.mjs +815 -0
- package/dist/schema-Gqcl-8G4.mjs.map +1 -0
- package/dist/scopes-BqPOKoKf.mjs +34 -0
- package/dist/scopes-BqPOKoKf.mjs.map +1 -0
- package/dist/search-YJKPIEV6.mjs +448 -0
- package/dist/search-YJKPIEV6.mjs.map +1 -0
- package/dist/sections-BR_e-wK5.mjs +346 -0
- package/dist/sections-BR_e-wK5.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +37 -31
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +22 -21
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-Dsj8hy3j.mjs +114 -0
- package/dist/seo-Dsj8hy3j.mjs.map +1 -0
- package/dist/seo-XvH4LNNp.mjs +133 -0
- package/dist/seo-XvH4LNNp.mjs.map +1 -0
- package/dist/service-BsVG05gS.mjs +150 -0
- package/dist/service-BsVG05gS.mjs.map +1 -0
- package/dist/session-user-DgKbYrlj.mjs +51 -0
- package/dist/session-user-DgKbYrlj.mjs.map +1 -0
- package/dist/settings-CNPUntkh.mjs +51 -0
- package/dist/settings-CNPUntkh.mjs.map +1 -0
- package/dist/settings-D5EHi0Tk.mjs +439 -0
- package/dist/settings-D5EHi0Tk.mjs.map +1 -0
- package/dist/settings-DSfE7wOa.mjs +61 -0
- package/dist/settings-DSfE7wOa.mjs.map +1 -0
- package/dist/setup-complete-B8W8sJ9v.mjs +26 -0
- package/dist/setup-complete-B8W8sJ9v.mjs.map +1 -0
- package/dist/setup-nonce-DnSBP260.mjs +25 -0
- package/dist/setup-nonce-DnSBP260.mjs.map +1 -0
- package/dist/site-settings-NGzdrt7O.mjs +50 -0
- package/dist/site-settings-NGzdrt7O.mjs.map +1 -0
- package/dist/site-url-D6JB7tLW.mjs +16 -0
- package/dist/site-url-D6JB7tLW.mjs.map +1 -0
- package/dist/snapshot-CdcwwWAf.mjs +414 -0
- package/dist/snapshot-CdcwwWAf.mjs.map +1 -0
- package/dist/ssrf-Dv0_tRpo.mjs +406 -0
- package/dist/ssrf-Dv0_tRpo.mjs.map +1 -0
- package/dist/stage-CUjhED3P.mjs +662 -0
- package/dist/stage-CUjhED3P.mjs.map +1 -0
- package/dist/staged-C36IWXff.mjs +659 -0
- package/dist/staged-C36IWXff.mjs.map +1 -0
- package/dist/state-CKouMCSY.mjs +153 -0
- package/dist/state-CKouMCSY.mjs.map +1 -0
- package/dist/status-lzyj4Uu7.mjs +30 -0
- package/dist/status-lzyj4Uu7.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-B-cWcTjJ.d.mts +1594 -0
- package/dist/storage-query-B-cWcTjJ.d.mts.map +1 -0
- package/dist/tar-DsTXX6ch.mjs +449 -0
- package/dist/tar-DsTXX6ch.mjs.map +1 -0
- package/dist/target-DLQCwp_Z.mjs +27 -0
- package/dist/target-DLQCwp_Z.mjs.map +1 -0
- package/dist/taxonomies-BlAjr4BL.mjs +697 -0
- package/dist/taxonomies-BlAjr4BL.mjs.map +1 -0
- package/dist/taxonomies-Byyo7LOZ.mjs +939 -0
- package/dist/taxonomies-Byyo7LOZ.mjs.map +1 -0
- package/dist/taxonomy-CKDwM61Y.mjs +525 -0
- package/dist/taxonomy-CKDwM61Y.mjs.map +1 -0
- package/dist/tokens-BojXlk49.mjs +171 -0
- package/dist/tokens-BojXlk49.mjs.map +1 -0
- package/dist/transaction-DLPQWik1.mjs +29 -0
- package/dist/transaction-DLPQWik1.mjs.map +1 -0
- package/dist/transfer-XSTh2BCr.mjs +8706 -0
- package/dist/transfer-XSTh2BCr.mjs.map +1 -0
- package/dist/transfer-download-DkoCDA9d.mjs +33 -0
- package/dist/transfer-download-DkoCDA9d.mjs.map +1 -0
- package/dist/transfer-iQ26J-RT.mjs +166 -0
- package/dist/transfer-iQ26J-RT.mjs.map +1 -0
- package/dist/transformations-C7RQabKQ.mjs +196 -0
- package/dist/transformations-C7RQabKQ.mjs.map +1 -0
- package/dist/transport-D3RulfD6.mjs +136 -0
- package/dist/transport-D3RulfD6.mjs.map +1 -0
- package/dist/transport-DhlZlf4D.d.mts +42 -0
- package/dist/transport-DhlZlf4D.d.mts.map +1 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs +51 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs.map +1 -0
- package/dist/turnstile-lqUiY7lP.mjs +53 -0
- package/dist/turnstile-lqUiY7lP.mjs.map +1 -0
- package/dist/types-4Dn9bZhu.mjs +77 -0
- package/dist/types-4Dn9bZhu.mjs.map +1 -0
- package/dist/types-5LSo7PPx.d.mts +85 -0
- package/dist/types-5LSo7PPx.d.mts.map +1 -0
- package/dist/types-BQ3hwYJT.d.mts +896 -0
- package/dist/types-BQ3hwYJT.d.mts.map +1 -0
- package/dist/types-BYEk7qo3.d.mts +198 -0
- package/dist/types-BYEk7qo3.d.mts.map +1 -0
- package/dist/types-CJKsWVFR.mjs +199 -0
- package/dist/types-CJKsWVFR.mjs.map +1 -0
- package/dist/types-Ca_w8mmY.d.mts +363 -0
- package/dist/types-Ca_w8mmY.d.mts.map +1 -0
- package/dist/types-CkE41ZAG.mjs +18 -0
- package/dist/types-CkE41ZAG.mjs.map +1 -0
- package/dist/types-D0aJW2uR.d.mts +1641 -0
- package/dist/types-D0aJW2uR.d.mts.map +1 -0
- package/dist/types-DbpN4Qto.d.mts +372 -0
- package/dist/types-DbpN4Qto.d.mts.map +1 -0
- package/dist/types-ILDI1sdY.mjs +16 -0
- package/dist/types-ILDI1sdY.mjs.map +1 -0
- package/dist/types-OC5c-edM.mjs +22 -0
- package/dist/types-OC5c-edM.mjs.map +1 -0
- package/dist/types-aOOxRSx6.mjs +103 -0
- package/dist/types-aOOxRSx6.mjs.map +1 -0
- package/dist/types-m1WbUffD.d.mts +198 -0
- package/dist/types-m1WbUffD.d.mts.map +1 -0
- package/dist/types-uxLoPBio.d.mts +124 -0
- package/dist/types-uxLoPBio.d.mts.map +1 -0
- package/dist/types-we5uR-tV.d.mts +287 -0
- package/dist/types-we5uR-tV.d.mts.map +1 -0
- package/dist/upload-attempts-DduMy6B0.mjs +32 -0
- package/dist/upload-attempts-DduMy6B0.mjs.map +1 -0
- package/dist/url-pattern-B3EwxAAk.mjs +33 -0
- package/dist/url-pattern-B3EwxAAk.mjs.map +1 -0
- package/dist/user-ElwQjTQT.mjs +171 -0
- package/dist/user-ElwQjTQT.mjs.map +1 -0
- package/dist/utils-BlAXmfOG.mjs +439 -0
- package/dist/utils-BlAXmfOG.mjs.map +1 -0
- package/dist/validate-CH0X5b2c.d.mts +468 -0
- package/dist/validate-CH0X5b2c.d.mts.map +1 -0
- package/dist/validate-CfgRpcjA.mjs +492 -0
- package/dist/validate-CfgRpcjA.mjs.map +1 -0
- package/dist/validation-DvYJtv4k.mjs +218 -0
- package/dist/validation-DvYJtv4k.mjs.map +1 -0
- package/dist/version-DgYjhTud.mjs +9 -0
- package/dist/version-DgYjhTud.mjs.map +1 -0
- package/dist/version-Dq71scUb.mjs +7 -0
- package/dist/version-Dq71scUb.mjs.map +1 -0
- package/dist/widgets-ChFIj0be.mjs +126 -0
- package/dist/widgets-ChFIj0be.mjs.map +1 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs +372 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs.map +1 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts +34 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts.map +1 -0
- package/dist/zod-generator-DmTKI-Ig.mjs +426 -0
- package/dist/zod-generator-DmTKI-Ig.mjs.map +1 -0
- package/package.json +7 -6
- package/src/api/handlers/content.ts +593 -16
- package/src/api/handlers/device-flow.ts +74 -21
- package/src/api/handlers/index.ts +1 -0
- package/src/api/handlers/manifest.ts +79 -5
- package/src/api/handlers/media-upload.ts +17 -71
- package/src/api/handlers/media.ts +97 -3
- package/src/api/handlers/relations.ts +638 -157
- package/src/api/handlers/revision.ts +30 -0
- package/src/api/handlers/schema.ts +403 -1
- package/src/api/handlers/snapshot.ts +257 -3
- package/src/api/handlers/staged-references.ts +142 -0
- package/src/api/handlers/validate-references.ts +146 -0
- package/src/api/schemas/content.ts +13 -0
- package/src/api/schemas/relations.ts +54 -44
- package/src/api/schemas/schema.ts +14 -0
- package/src/astro/integration/routes.ts +15 -19
- package/src/astro/integration/vite-config.ts +10 -4
- package/src/astro/middleware.ts +1 -0
- package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +11 -54
- package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
- package/src/astro/routes/api/oauth/device/authorize.ts +33 -4
- package/src/astro/routes/api/relations/index.ts +4 -4
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +6 -2
- package/src/astro/routes/api/setup/index.ts +66 -23
- package/src/astro/routes/api/snapshot.ts +2 -1
- package/src/astro/types.ts +10 -0
- package/src/cleanup.ts +10 -0
- package/src/cli/commands/export-seed.ts +510 -89
- package/src/components/Columns.astro +3 -1
- package/src/components/Cover.astro +3 -1
- package/src/components/WidgetArea.astro +3 -2
- package/src/database/migrations/086_relations_structural.ts +197 -0
- package/src/database/migrations/087_reference_field_relations.ts +407 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/reference-backfill.ts +141 -0
- package/src/database/repositories/content.ts +43 -8
- package/src/database/repositories/media.ts +40 -1
- package/src/database/repositories/redirect.ts +17 -34
- package/src/database/repositories/relation.ts +620 -208
- package/src/database/repositories/revision.ts +16 -0
- package/src/database/repositories/types.ts +38 -0
- package/src/database/transaction.ts +12 -1
- package/src/database/types.ts +14 -5
- package/src/emdash-runtime.ts +114 -11
- package/src/index.ts +11 -0
- package/src/loader.ts +169 -22
- package/src/mcp/server.ts +13 -48
- package/src/query.ts +455 -25
- package/src/references/field-map.ts +115 -0
- package/src/references/resolve.ts +160 -0
- package/src/references/staged.ts +117 -0
- package/src/references/types.ts +16 -0
- package/src/registry/artifact-fetch.ts +45 -271
- package/src/schema/registry.ts +99 -24
- package/src/schema/types.ts +58 -0
- package/src/schema/zod-generator.ts +67 -1
- package/src/seed/apply.ts +841 -103
- package/src/seed/types.ts +36 -2
- package/src/seed/validate.ts +78 -2
- package/src/transfer/analyze/unique-keys.ts +3 -12
- package/src/transfer/analyze/validate.ts +65 -39
- package/src/transfer/analyze/values.ts +12 -1
- package/src/transfer/export/readers.ts +12 -8
- package/src/transfer/format/columns.ts +26 -6
- package/src/transfer/format/kinds.ts +21 -5
- package/src/transfer/import/context.ts +8 -1
- package/src/transfer/ops/package-index.ts +1 -1
- package/dist/action-token-DYwe4Pk0.mjs +0 -26
- package/dist/action-token-DYwe4Pk0.mjs.map +0 -1
- package/dist/activation-LOkDM5WT.mjs +0 -382
- package/dist/activation-LOkDM5WT.mjs.map +0 -1
- package/dist/adapters-B64LbYcB.d.mts +0 -171
- package/dist/adapters-B64LbYcB.d.mts.map +0 -1
- package/dist/allowed-origins-CHB8oZNM.mjs +0 -116
- package/dist/allowed-origins-CHB8oZNM.mjs.map +0 -1
- package/dist/api-cFFZpyS0.mjs +0 -4718
- package/dist/api-cFFZpyS0.mjs.map +0 -1
- package/dist/api-tokens-s4i4aUp_.mjs +0 -166
- package/dist/api-tokens-s4i4aUp_.mjs.map +0 -1
- package/dist/apply-CoT603H3.mjs +0 -1163
- package/dist/apply-CoT603H3.mjs.map +0 -1
- package/dist/approvals-CqMfNxak.mjs +0 -460
- package/dist/approvals-CqMfNxak.mjs.map +0 -1
- package/dist/artifact-fetch-DZMOGZ3-.mjs +0 -818
- package/dist/artifact-fetch-DZMOGZ3-.mjs.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.d.mts +0 -8
- package/dist/astro/routes/api/relations/_id_/translations.d.mts.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +0 -47
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +0 -1
- package/dist/audit-RfCugiSB.mjs +0 -127
- package/dist/audit-RfCugiSB.mjs.map +0 -1
- package/dist/authoritative-records-CoJvBXAD.mjs +0 -5172
- package/dist/authoritative-records-CoJvBXAD.mjs.map +0 -1
- package/dist/authorize-seCifOMJ.mjs +0 -49
- package/dist/authorize-seCifOMJ.mjs.map +0 -1
- package/dist/backup-CBu0LrXf.mjs +0 -246
- package/dist/backup-CBu0LrXf.mjs.map +0 -1
- package/dist/block-type-registry-DUI_3KxT.mjs +0 -6709
- package/dist/block-type-registry-DUI_3KxT.mjs.map +0 -1
- package/dist/block-types-BmZmLmAD.mjs +0 -132
- package/dist/block-types-BmZmLmAD.mjs.map +0 -1
- package/dist/block-values-C_VIPr5t.mjs +0 -175
- package/dist/block-values-C_VIPr5t.mjs.map +0 -1
- package/dist/byline-DYmkXqvo.mjs +0 -909
- package/dist/byline-DYmkXqvo.mjs.map +0 -1
- package/dist/byline-fields-D28AT-Fh.mjs +0 -123
- package/dist/byline-fields-D28AT-Fh.mjs.map +0 -1
- package/dist/byline-registry-gnKscbQX.mjs +0 -406
- package/dist/byline-registry-gnKscbQX.mjs.map +0 -1
- package/dist/bylines-BPwJqoYH.mjs +0 -232
- package/dist/bylines-BPwJqoYH.mjs.map +0 -1
- package/dist/bylines-ukLaYpVZ.mjs +0 -214
- package/dist/bylines-ukLaYpVZ.mjs.map +0 -1
- package/dist/cache-m7UEkRFV.mjs +0 -108
- package/dist/cache-m7UEkRFV.mjs.map +0 -1
- package/dist/canonical-YhEQezjg.mjs +0 -174
- package/dist/canonical-YhEQezjg.mjs.map +0 -1
- package/dist/capture-triggers-kJyl_yyM.mjs +0 -362
- package/dist/capture-triggers-kJyl_yyM.mjs.map +0 -1
- package/dist/challenge-store-ppU6Uv13.mjs +0 -51
- package/dist/challenge-store-ppU6Uv13.mjs.map +0 -1
- package/dist/checksum-B2IINIlN.mjs +0 -162
- package/dist/checksum-B2IINIlN.mjs.map +0 -1
- package/dist/chrome-tags-DApCQSIk.mjs +0 -24
- package/dist/chrome-tags-DApCQSIk.mjs.map +0 -1
- package/dist/chunks-Dms7Uxbt.mjs +0 -25
- package/dist/chunks-Dms7Uxbt.mjs.map +0 -1
- package/dist/collection-deletion-BIm28mo3.mjs +0 -436
- package/dist/collection-deletion-BIm28mo3.mjs.map +0 -1
- package/dist/collection-deletion-processor-Br6rxs3u.mjs +0 -217
- package/dist/collection-deletion-processor-Br6rxs3u.mjs.map +0 -1
- package/dist/collection-slugs-cache-CjGk__zp.mjs +0 -85
- package/dist/collection-slugs-cache-CjGk__zp.mjs.map +0 -1
- package/dist/comment-CrBl22OF.mjs +0 -313
- package/dist/comment-CrBl22OF.mjs.map +0 -1
- package/dist/comment-reaction-JEQ2Fpd8.mjs +0 -85
- package/dist/comment-reaction-JEQ2Fpd8.mjs.map +0 -1
- package/dist/comments-2ah9du9y.mjs +0 -195
- package/dist/comments-2ah9du9y.mjs.map +0 -1
- package/dist/comments-fHZ8ON9O.mjs +0 -99
- package/dist/comments-fHZ8ON9O.mjs.map +0 -1
- package/dist/components-CXbq7CSM.mjs +0 -108
- package/dist/components-CXbq7CSM.mjs.map +0 -1
- package/dist/config-5ii2haYu.d.mts +0 -6528
- package/dist/config-5ii2haYu.d.mts.map +0 -1
- package/dist/config-IhybvkIQ.mjs +0 -242
- package/dist/config-IhybvkIQ.mjs.map +0 -1
- package/dist/config-Py43JK9r.d.mts +0 -39
- package/dist/config-Py43JK9r.d.mts.map +0 -1
- package/dist/content-DFaIEDj9.mjs +0 -2281
- package/dist/content-DFaIEDj9.mjs.map +0 -1
- package/dist/content-list-query-Dra4Dalc.d.mts +0 -26
- package/dist/content-list-query-Dra4Dalc.d.mts.map +0 -1
- package/dist/content-policy-DFNw91-d.mjs +0 -46
- package/dist/content-policy-DFNw91-d.mjs.map +0 -1
- package/dist/content-repair-Q8IUrpLL.mjs +0 -442
- package/dist/content-repair-Q8IUrpLL.mjs.map +0 -1
- package/dist/context-BeGccdUX.mjs +0 -1921
- package/dist/context-BeGccdUX.mjs.map +0 -1
- package/dist/cron-7DCJwPXq.mjs +0 -284
- package/dist/cron-7DCJwPXq.mjs.map +0 -1
- package/dist/dashboard-DjrB-xxZ.mjs +0 -151
- package/dist/dashboard-DjrB-xxZ.mjs.map +0 -1
- package/dist/default-DQ6vsviu.mjs +0 -81
- package/dist/default-DQ6vsviu.mjs.map +0 -1
- package/dist/deferred-tasks-BPxXUB4x.d.mts +0 -9
- package/dist/deferred-tasks-BPxXUB4x.d.mts.map +0 -1
- package/dist/dev-typegen-CZaPLl3V.mjs +0 -29
- package/dist/dev-typegen-CZaPLl3V.mjs.map +0 -1
- package/dist/device-flow-CRd6DXmW.mjs +0 -466
- package/dist/device-flow-CRd6DXmW.mjs.map +0 -1
- package/dist/digest-BarSh-pN.mjs +0 -194
- package/dist/digest-BarSh-pN.mjs.map +0 -1
- package/dist/direct-executor-BmuFJJZV.mjs +0 -104
- package/dist/direct-executor-BmuFJJZV.mjs.map +0 -1
- package/dist/dist-BNwANFJR.mjs +0 -810
- package/dist/dist-BNwANFJR.mjs.map +0 -1
- package/dist/email-console-bJn3ctqA.mjs +0 -50
- package/dist/email-console-bJn3ctqA.mjs.map +0 -1
- package/dist/email-locale-CN6WAMx0.mjs +0 -25
- package/dist/email-locale-CN6WAMx0.mjs.map +0 -1
- package/dist/emdash-runtime-DAjghyEG.mjs +0 -4186
- package/dist/emdash-runtime-DAjghyEG.mjs.map +0 -1
- package/dist/enrich-Dl3kZ-lP.mjs +0 -194
- package/dist/enrich-Dl3kZ-lP.mjs.map +0 -1
- package/dist/entry-lock-BJYdBfXb.mjs +0 -1097
- package/dist/entry-lock-BJYdBfXb.mjs.map +0 -1
- package/dist/entry-lock-DHQOxN7R.mjs +0 -163
- package/dist/entry-lock-DHQOxN7R.mjs.map +0 -1
- package/dist/entry-lock-DVhCt49A.d.mts +0 -4368
- package/dist/entry-lock-DVhCt49A.d.mts.map +0 -1
- package/dist/entry-locks-D0foLdjQ.mjs +0 -167
- package/dist/entry-locks-D0foLdjQ.mjs.map +0 -1
- package/dist/error-CfvOHP0M.mjs +0 -90
- package/dist/error-CfvOHP0M.mjs.map +0 -1
- package/dist/errors-BF0_LFhW.mjs +0 -460
- package/dist/errors-BF0_LFhW.mjs.map +0 -1
- package/dist/errors-DgE1zJGG.mjs +0 -120
- package/dist/errors-DgE1zJGG.mjs.map +0 -1
- package/dist/escape-CuaZhZvL.mjs +0 -9
- package/dist/escape-CuaZhZvL.mjs.map +0 -1
- package/dist/fence-CMDXJYc_.mjs +0 -162
- package/dist/fence-CMDXJYc_.mjs.map +0 -1
- package/dist/field-defs-cache-HIgBbqZZ.mjs +0 -77
- package/dist/field-defs-cache-HIgBbqZZ.mjs.map +0 -1
- package/dist/focal-point-Gr34o-4o.mjs +0 -23
- package/dist/focal-point-Gr34o-4o.mjs.map +0 -1
- package/dist/fts-manager-S-K0laoS.mjs +0 -443
- package/dist/fts-manager-S-K0laoS.mjs.map +0 -1
- package/dist/gc-DjKY0Ay1.mjs +0 -75
- package/dist/gc-DjKY0Ay1.mjs.map +0 -1
- package/dist/hash-SDAW6zC-.mjs +0 -37
- package/dist/hash-SDAW6zC-.mjs.map +0 -1
- package/dist/hook-result-B5bXDgS2.d.mts +0 -31
- package/dist/hook-result-B5bXDgS2.d.mts.map +0 -1
- package/dist/hreflang-D5uNnsGJ.d.mts +0 -50
- package/dist/hreflang-D5uNnsGJ.d.mts.map +0 -1
- package/dist/hreflang-DMFBL2eb.mjs +0 -105
- package/dist/hreflang-DMFBL2eb.mjs.map +0 -1
- package/dist/http-route-dispatch-BitqzwMy.mjs +0 -339
- package/dist/http-route-dispatch-BitqzwMy.mjs.map +0 -1
- package/dist/identity-IyNWwXr6.mjs +0 -35
- package/dist/identity-IyNWwXr6.mjs.map +0 -1
- package/dist/import-C3JZplWq.mjs +0 -2020
- package/dist/import-C3JZplWq.mjs.map +0 -1
- package/dist/index-D-hdtLe8.d.mts +0 -623
- package/dist/index-D-hdtLe8.d.mts.map +0 -1
- package/dist/install-finalization-DfM1fj5x.mjs +0 -58
- package/dist/install-finalization-DfM1fj5x.mjs.map +0 -1
- package/dist/keys-yxLm5l35.mjs +0 -61
- package/dist/keys-yxLm5l35.mjs.map +0 -1
- package/dist/kinds-CRu_T5T5.mjs +0 -961
- package/dist/kinds-CRu_T5T5.mjs.map +0 -1
- package/dist/lifecycle-BzeGPeQ-.mjs +0 -25
- package/dist/lifecycle-BzeGPeQ-.mjs.map +0 -1
- package/dist/load-XgJiE6_3.mjs +0 -28
- package/dist/load-XgJiE6_3.mjs.map +0 -1
- package/dist/loader-BzqeR1ZN.mjs +0 -1086
- package/dist/loader-BzqeR1ZN.mjs.map +0 -1
- package/dist/loops-BQSzv5Zn.mjs +0 -203
- package/dist/loops-BQSzv5Zn.mjs.map +0 -1
- package/dist/manifest-builder-B8zR-73J.mjs +0 -189
- package/dist/manifest-builder-B8zR-73J.mjs.map +0 -1
- package/dist/manifest-schema-CY3zng_M.mjs +0 -492
- package/dist/manifest-schema-CY3zng_M.mjs.map +0 -1
- package/dist/media-Pu1L6xir.mjs +0 -408
- package/dist/media-Pu1L6xir.mjs.map +0 -1
- package/dist/media-Qp5S3eH3.mjs +0 -355
- package/dist/media-Qp5S3eH3.mjs.map +0 -1
- package/dist/media-allowlist-BSoa9Vvm.mjs +0 -44
- package/dist/media-allowlist-BSoa9Vvm.mjs.map +0 -1
- package/dist/media-folders-BE0oo2eX.mjs +0 -210
- package/dist/media-folders-BE0oo2eX.mjs.map +0 -1
- package/dist/media-h7tOiDLj.mjs +0 -221
- package/dist/media-h7tOiDLj.mjs.map +0 -1
- package/dist/media-url-jArBpzIG.mjs +0 -43
- package/dist/media-url-jArBpzIG.mjs.map +0 -1
- package/dist/media-usage-My-Vi-ex.mjs +0 -1629
- package/dist/media-usage-My-Vi-ex.mjs.map +0 -1
- package/dist/media-usage-activation-HKp7zk7W.mjs +0 -78
- package/dist/media-usage-activation-HKp7zk7W.mjs.map +0 -1
- package/dist/media-usage-work-C2OZLCAd.mjs +0 -586
- package/dist/media-usage-work-C2OZLCAd.mjs.map +0 -1
- package/dist/media-usage-work-DwUNbgvS.mjs +0 -152
- package/dist/media-usage-work-DwUNbgvS.mjs.map +0 -1
- package/dist/menus-BM7BPLOb.mjs +0 -139
- package/dist/menus-BM7BPLOb.mjs.map +0 -1
- package/dist/menus-ITeAbcIF.mjs +0 -753
- package/dist/menus-ITeAbcIF.mjs.map +0 -1
- package/dist/menus-TsSGmSR4.mjs +0 -3608
- package/dist/menus-TsSGmSR4.mjs.map +0 -1
- package/dist/mime-ChLqYwDk.mjs +0 -36
- package/dist/mime-ChLqYwDk.mjs.map +0 -1
- package/dist/mode-CCuKXUci.mjs +0 -23
- package/dist/mode-CCuKXUci.mjs.map +0 -1
- package/dist/node-sqlite-compat-CONMsl-x.mjs +0 -46
- package/dist/node-sqlite-compat-CONMsl-x.mjs.map +0 -1
- package/dist/normalize-CO2P8-iE.mjs +0 -191
- package/dist/normalize-CO2P8-iE.mjs.map +0 -1
- package/dist/oauth-authorization-DlMIL5_h.mjs +0 -274
- package/dist/oauth-authorization-DlMIL5_h.mjs.map +0 -1
- package/dist/oauth-clients-Djq9r_KP.mjs +0 -266
- package/dist/oauth-clients-Djq9r_KP.mjs.map +0 -1
- package/dist/oauth-state-store-BbjnZXNC.mjs +0 -50
- package/dist/oauth-state-store-BbjnZXNC.mjs.map +0 -1
- package/dist/oauth-user-lookup-vue9a64A.mjs +0 -26
- package/dist/oauth-user-lookup-vue9a64A.mjs.map +0 -1
- package/dist/options-SQCHQCPH.d.mts +0 -81
- package/dist/options-SQCHQCPH.d.mts.map +0 -1
- package/dist/parse-CVgO-Qai.d.mts +0 -168
- package/dist/parse-CVgO-Qai.d.mts.map +0 -1
- package/dist/parse-DY6OD1j_.mjs +0 -81
- package/dist/parse-DY6OD1j_.mjs.map +0 -1
- package/dist/passkey-config-X_H8128a.mjs +0 -46
- package/dist/passkey-config-X_H8128a.mjs.map +0 -1
- package/dist/paths-JxokKIbr.mjs +0 -77
- package/dist/paths-JxokKIbr.mjs.map +0 -1
- package/dist/patterns-BhAvqO0S.mjs +0 -145
- package/dist/patterns-BhAvqO0S.mjs.map +0 -1
- package/dist/placeholder-MSEd8gty.d.mts +0 -306
- package/dist/placeholder-MSEd8gty.d.mts.map +0 -1
- package/dist/plan-xjcWrAah.mjs +0 -135
- package/dist/plan-xjcWrAah.mjs.map +0 -1
- package/dist/plugins-DUXUt8B9.mjs +0 -277
- package/dist/plugins-DUXUt8B9.mjs.map +0 -1
- package/dist/policy-CUvwAARc.mjs +0 -45
- package/dist/policy-CUvwAARc.mjs.map +0 -1
- package/dist/portable-text-5O_ZGUjB.mjs +0 -307
- package/dist/portable-text-5O_ZGUjB.mjs.map +0 -1
- package/dist/preview-CIUcPYr6.mjs +0 -107
- package/dist/preview-CIUcPYr6.mjs.map +0 -1
- package/dist/protocol-B97DZaFr.d.mts +0 -61
- package/dist/protocol-B97DZaFr.d.mts.map +0 -1
- package/dist/public-submission-BFBUrqst.mjs +0 -250
- package/dist/public-submission-BFBUrqst.mjs.map +0 -1
- package/dist/public-url-Bn7U0D7-.mjs +0 -101
- package/dist/public-url-Bn7U0D7-.mjs.map +0 -1
- package/dist/query-B48peoRT.mjs +0 -890
- package/dist/query-B48peoRT.mjs.map +0 -1
- package/dist/query-C4IH0uhR.mjs +0 -41
- package/dist/query-C4IH0uhR.mjs.map +0 -1
- package/dist/rate-limit-BZ6nybgc.mjs +0 -120
- package/dist/rate-limit-BZ6nybgc.mjs.map +0 -1
- package/dist/receipt-B4wJj5Jq.mjs +0 -43
- package/dist/receipt-B4wJj5Jq.mjs.map +0 -1
- package/dist/redirect-Cd1E7VUt.mjs +0 -17
- package/dist/redirect-Cd1E7VUt.mjs.map +0 -1
- package/dist/redirect-iJf5fltD.mjs +0 -415
- package/dist/redirect-iJf5fltD.mjs.map +0 -1
- package/dist/redirects-CYu1u1aK.mjs +0 -446
- package/dist/redirects-CYu1u1aK.mjs.map +0 -1
- package/dist/redirects-Cv9apQKj.mjs +0 -148
- package/dist/redirects-Cv9apQKj.mjs.map +0 -1
- package/dist/relation-M4NUCb0b.mjs +0 -334
- package/dist/relation-M4NUCb0b.mjs.map +0 -1
- package/dist/relations-CCif47Oq.mjs +0 -403
- package/dist/relations-CCif47Oq.mjs.map +0 -1
- package/dist/relations-CK9CYUyr.mjs +0 -310
- package/dist/relations-CK9CYUyr.mjs.map +0 -1
- package/dist/request-cache-DzLYKm_x.mjs +0 -104
- package/dist/request-cache-DzLYKm_x.mjs.map +0 -1
- package/dist/request-meta-sZXt3sRo.mjs +0 -141
- package/dist/request-meta-sZXt3sRo.mjs.map +0 -1
- package/dist/resolve-2WbQsCvT.mjs +0 -199
- package/dist/resolve-2WbQsCvT.mjs.map +0 -1
- package/dist/route-wire--1hLuACz.mjs +0 -197
- package/dist/route-wire--1hLuACz.mjs.map +0 -1
- package/dist/routes-CUsM40Cc.mjs +0 -272
- package/dist/routes-CUsM40Cc.mjs.map +0 -1
- package/dist/runner-1y4J9fJB.mjs +0 -5742
- package/dist/runner-1y4J9fJB.mjs.map +0 -1
- package/dist/runner-D5_LzKXI.d.mts +0 -68
- package/dist/runner-D5_LzKXI.d.mts.map +0 -1
- package/dist/schema-BABiRdsH.mjs +0 -13
- package/dist/schema-BABiRdsH.mjs.map +0 -1
- package/dist/schema-Du3MzCG0.mjs +0 -446
- package/dist/schema-Du3MzCG0.mjs.map +0 -1
- package/dist/scopes-Dbk-ElhT.mjs +0 -34
- package/dist/scopes-Dbk-ElhT.mjs.map +0 -1
- package/dist/search-Bt1PL1jf.mjs +0 -448
- package/dist/search-Bt1PL1jf.mjs.map +0 -1
- package/dist/sections-Ddptx_o9.mjs +0 -346
- package/dist/sections-Ddptx_o9.mjs.map +0 -1
- package/dist/seo-CZT2oLtT.mjs +0 -114
- package/dist/seo-CZT2oLtT.mjs.map +0 -1
- package/dist/seo-D5w3-Azy.mjs +0 -133
- package/dist/seo-D5w3-Azy.mjs.map +0 -1
- package/dist/service-DuykXPyW.mjs +0 -150
- package/dist/service-DuykXPyW.mjs.map +0 -1
- package/dist/session-user-BhaVp8w0.mjs +0 -51
- package/dist/session-user-BhaVp8w0.mjs.map +0 -1
- package/dist/settings-2xNYr90o.mjs +0 -51
- package/dist/settings-2xNYr90o.mjs.map +0 -1
- package/dist/settings-CgjRWGW9.mjs +0 -439
- package/dist/settings-CgjRWGW9.mjs.map +0 -1
- package/dist/settings-DYidIB26.mjs +0 -61
- package/dist/settings-DYidIB26.mjs.map +0 -1
- package/dist/setup-complete-bOogcHWG.mjs +0 -26
- package/dist/setup-complete-bOogcHWG.mjs.map +0 -1
- package/dist/setup-nonce-0EGuKM4s.mjs +0 -25
- package/dist/setup-nonce-0EGuKM4s.mjs.map +0 -1
- package/dist/site-settings-DOgRUoFX.mjs +0 -50
- package/dist/site-settings-DOgRUoFX.mjs.map +0 -1
- package/dist/site-url-BU_bbxwj.mjs +0 -16
- package/dist/site-url-BU_bbxwj.mjs.map +0 -1
- package/dist/snapshot-CugwUqKQ.mjs +0 -237
- package/dist/snapshot-CugwUqKQ.mjs.map +0 -1
- package/dist/ssrf-CJUnJymJ.mjs +0 -406
- package/dist/ssrf-CJUnJymJ.mjs.map +0 -1
- package/dist/stage-DgrBz_du.mjs +0 -662
- package/dist/stage-DgrBz_du.mjs.map +0 -1
- package/dist/state-DDiPySSG.mjs +0 -153
- package/dist/state-DDiPySSG.mjs.map +0 -1
- package/dist/status-DZKIG4a9.mjs +0 -30
- package/dist/status-DZKIG4a9.mjs.map +0 -1
- package/dist/storage-query-Bdv7A62k.d.mts +0 -1576
- package/dist/storage-query-Bdv7A62k.d.mts.map +0 -1
- package/dist/tar-_1AgTYFu.mjs +0 -449
- package/dist/tar-_1AgTYFu.mjs.map +0 -1
- package/dist/target-_7pn2Gbg.mjs +0 -27
- package/dist/target-_7pn2Gbg.mjs.map +0 -1
- package/dist/taxonomies-C1IwNe8Q.mjs +0 -697
- package/dist/taxonomies-C1IwNe8Q.mjs.map +0 -1
- package/dist/taxonomies-C_XMoRcX.mjs +0 -939
- package/dist/taxonomies-C_XMoRcX.mjs.map +0 -1
- package/dist/taxonomy-C3Fu1YeH.mjs +0 -525
- package/dist/taxonomy-C3Fu1YeH.mjs.map +0 -1
- package/dist/tokens-u78jETkX.mjs +0 -171
- package/dist/tokens-u78jETkX.mjs.map +0 -1
- package/dist/transaction-BcJO4Tmc.mjs +0 -29
- package/dist/transaction-BcJO4Tmc.mjs.map +0 -1
- package/dist/transfer-BhUCrgDc.mjs +0 -8675
- package/dist/transfer-BhUCrgDc.mjs.map +0 -1
- package/dist/transfer-DIGvR9Af.mjs +0 -166
- package/dist/transfer-DIGvR9Af.mjs.map +0 -1
- package/dist/transfer-download-Pml7RMio.mjs +0 -33
- package/dist/transfer-download-Pml7RMio.mjs.map +0 -1
- package/dist/transformations-9gfpwY65.mjs +0 -196
- package/dist/transformations-9gfpwY65.mjs.map +0 -1
- package/dist/transport-BIfH7_hx.d.mts +0 -42
- package/dist/transport-BIfH7_hx.d.mts.map +0 -1
- package/dist/transport-DKWIq53q.mjs +0 -136
- package/dist/transport-DKWIq53q.mjs.map +0 -1
- package/dist/trusted-proxy-tKiVtyTD.mjs +0 -51
- package/dist/trusted-proxy-tKiVtyTD.mjs.map +0 -1
- package/dist/turnstile-DpsoyOfg.mjs +0 -53
- package/dist/turnstile-DpsoyOfg.mjs.map +0 -1
- package/dist/types-B4sUC2p1.d.mts +0 -198
- package/dist/types-B4sUC2p1.d.mts.map +0 -1
- package/dist/types-B7Lmsh1E.d.mts +0 -887
- package/dist/types-B7Lmsh1E.d.mts.map +0 -1
- package/dist/types-BZakh7Ym.mjs +0 -22
- package/dist/types-BZakh7Ym.mjs.map +0 -1
- package/dist/types-B_CppEmv.d.mts +0 -264
- package/dist/types-B_CppEmv.d.mts.map +0 -1
- package/dist/types-BcrBrE6-.mjs +0 -159
- package/dist/types-BcrBrE6-.mjs.map +0 -1
- package/dist/types-BkUg2yHx.mjs +0 -92
- package/dist/types-BkUg2yHx.mjs.map +0 -1
- package/dist/types-CAZgq9fO.d.mts +0 -124
- package/dist/types-CAZgq9fO.d.mts.map +0 -1
- package/dist/types-Cd-O03VG.d.mts +0 -363
- package/dist/types-Cd-O03VG.d.mts.map +0 -1
- package/dist/types-Cr-Kg-3D.d.mts +0 -1641
- package/dist/types-Cr-Kg-3D.d.mts.map +0 -1
- package/dist/types-D2fvWd1i.d.mts +0 -359
- package/dist/types-D2fvWd1i.d.mts.map +0 -1
- package/dist/types-D7HUsguf.mjs +0 -77
- package/dist/types-D7HUsguf.mjs.map +0 -1
- package/dist/types-DA1Te3Oy.d.mts +0 -198
- package/dist/types-DA1Te3Oy.d.mts.map +0 -1
- package/dist/types-DhV6Q5bP.mjs +0 -18
- package/dist/types-DhV6Q5bP.mjs.map +0 -1
- package/dist/types-DnnVSl6Y.d.mts +0 -85
- package/dist/types-DnnVSl6Y.d.mts.map +0 -1
- package/dist/types-VT4-BugW.mjs +0 -16
- package/dist/types-VT4-BugW.mjs.map +0 -1
- package/dist/upload-attempts-B68ZGNu9.mjs +0 -32
- package/dist/upload-attempts-B68ZGNu9.mjs.map +0 -1
- package/dist/url-pattern-CCeZMGOh.mjs +0 -33
- package/dist/url-pattern-CCeZMGOh.mjs.map +0 -1
- package/dist/user-DDSL-sGw.mjs +0 -171
- package/dist/user-DDSL-sGw.mjs.map +0 -1
- package/dist/utils-DdhmO9w9.mjs +0 -439
- package/dist/utils-DdhmO9w9.mjs.map +0 -1
- package/dist/validate-CHosPEhs.mjs +0 -453
- package/dist/validate-CHosPEhs.mjs.map +0 -1
- package/dist/validate-CM79QXYE.d.mts +0 -432
- package/dist/validate-CM79QXYE.d.mts.map +0 -1
- package/dist/validation-BFecQczG.mjs +0 -218
- package/dist/validation-BFecQczG.mjs.map +0 -1
- package/dist/version-BRZXVifl.mjs +0 -9
- package/dist/version-BRZXVifl.mjs.map +0 -1
- package/dist/version-DUQDHgrf.mjs +0 -7
- package/dist/version-DUQDHgrf.mjs.map +0 -1
- package/dist/widgets-WdV72brA.mjs +0 -126
- package/dist/widgets-WdV72brA.mjs.map +0 -1
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts +0 -34
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts.map +0 -1
- package/dist/wxr-taxonomies-DP6ESgMN.mjs +0 -372
- package/dist/wxr-taxonomies-DP6ESgMN.mjs.map +0 -1
- package/dist/zod-generator-D6uE4WiS.mjs +0 -389
- package/dist/zod-generator-D6uE4WiS.mjs.map +0 -1
- package/src/astro/routes/api/relations/[id]/translations.ts +0 -33
- /package/dist/{api-tokens-CE1ECIg0.mjs → api-tokens-FaG1zPsj.mjs} +0 -0
- /package/dist/{ssrf-DpBH7aOt.mjs → ssrf-DZOt8Qof.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-Gqcl-8G4.mjs","names":[],"sources":["../src/database/reference-backfill.ts","../src/api/handlers/schema.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { chunks, SQL_BATCH_SIZE } from \"../utils/chunks.js\";\nimport { currentTimestampValue, tableExists } from \"./dialect-helpers.js\";\nimport { REFERENCE_INSERT_BATCH_SIZE } from \"./repositories/relation.js\";\nimport { validateIdentifier } from \"./validate.js\";\n\n/** What to copy, and which relation to copy it into. */\nexport interface ReferenceBackfill {\n\t/** Collection owning the field, the relation's parent end. */\n\tparentCollection: string;\n\t/** The relation's child end, where the column's ids resolve. */\n\tchildCollection: string;\n\tfieldSlug: string;\n\trelationId: string;\n\t/** The relation's limit for this side. `null` is unlimited. */\n\tmaxChildren: number | null;\n}\n\n/** The ids one column value holds. */\nfunction parseColumnIds(value: unknown): string[] {\n\tif (typeof value !== \"string\" || value.length === 0) return [];\n\tif (!value.startsWith(\"[\")) return [value];\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(value);\n\t} catch {\n\t\treturn [value];\n\t}\n\tif (!Array.isArray(parsed)) return [];\n\treturn parsed.filter((entry): entry is string => typeof entry === \"string\" && entry.length > 0);\n}\n\n/**\n * Copy a reference field's column values in as relation edges.\n *\n * A reference field created before relations existed holds its selection in a\n * TEXT column: one entry id, or a JSON array of them for a multiple-reference\n * field (`serializeValue` stringifies the array). Binding the field to a relation\n * moves that selection into `_emdash_content_references`, and this is the copy.\n *\n * The column is not touched. On a site that predates pickers it was a free-text\n * box, so it can hold anything an editor typed, and only the ids that resolve to\n * an entry become edges — clearing it would destroy the rest. Nothing writes to\n * it once the field is bound and typegen stops declaring the key, but a content\n * read still reports the frozen value in `data` beside the live `references`.\n *\n * Both ends of an edge are translation groups, so the locale siblings of one\n * entry contribute to the same parent group. They are read in a fixed order and\n * their ids deduped, and the result is capped at the relation's limit — a\n * single-reference field whose locale rows point at different entries keeps the\n * first rather than storing a selection the relation forbids.\n *\n * Every insert is `ON CONFLICT DO NOTHING` against the edge table's unique\n * constraint, so running this twice adds nothing the first run already wrote.\n *\n * Migration 077 carries its own copy of this for the upgrade path. A migration\n * must not share a module with the handler layer — the bundler then puts the two\n * in chunks that cycle through the migration runner, and the built package throws\n * on import — and a shipped migration has to keep behaving the way it did anyway.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- runs against a migration's untyped Kysely as well as the app's\nexport async function backfillReferenceEdges(\n\tdb: Kysely<any>,\n\tbackfill: ReferenceBackfill,\n): Promise<void> {\n\tconst parentTable = `ec_${backfill.parentCollection}`;\n\tconst childTable = `ec_${backfill.childCollection}`;\n\tvalidateIdentifier(parentTable, \"content table name\");\n\tvalidateIdentifier(childTable, \"content table name\");\n\tvalidateIdentifier(backfill.fieldSlug, \"content field name\");\n\n\tif (!(await tableExists(db, parentTable)) || !(await tableExists(db, childTable))) return;\n\n\tconst entries = await sql<{ translation_group: string | null; value: unknown }>`\n\t\tSELECT translation_group, ${sql.ref(backfill.fieldSlug)} AS value\n\t\tFROM ${sql.ref(parentTable)}\n\t\tWHERE ${sql.ref(backfill.fieldSlug)} IS NOT NULL\n\t\tORDER BY locale, id\n\t`.execute(db);\n\n\t// Parent group -> the child entry ids it selects, in order, deduped.\n\tconst selections = new Map<string, string[]>();\n\tfor (const entry of entries.rows) {\n\t\tif (!entry.translation_group) continue;\n\t\tconst existing = selections.get(entry.translation_group) ?? [];\n\t\tfor (const id of parseColumnIds(entry.value)) {\n\t\t\tif (!existing.includes(id)) existing.push(id);\n\t\t}\n\t\tselections.set(entry.translation_group, existing);\n\t}\n\tif (selections.size === 0) return;\n\n\tconst childIds = [...new Set([...selections.values()].flat())];\n\tconst childGroups = new Map<string, string>();\n\tfor (const batch of chunks(childIds, SQL_BATCH_SIZE)) {\n\t\t// oxlint-disable-next-line no-await-in-loop -- one statement per bind-parameter batch\n\t\tconst resolved = await sql<{ id: string; translation_group: string | null }>`\n\t\t\tSELECT id, translation_group\n\t\t\tFROM ${sql.ref(childTable)}\n\t\t\tWHERE id IN (${sql.join(batch)})\n\t\t`.execute(db);\n\t\tfor (const row of resolved.rows) {\n\t\t\tif (row.translation_group) childGroups.set(row.id, row.translation_group);\n\t\t}\n\t}\n\n\tconst now = currentTimestampValue(db);\n\tconst rows: Array<{ parentGroup: string; childGroup: string; sortOrder: number }> = [];\n\tfor (const parentGroup of [...selections.keys()].toSorted()) {\n\t\tconst groups: string[] = [];\n\t\tfor (const id of selections.get(parentGroup) ?? []) {\n\t\t\tconst group = childGroups.get(id);\n\t\t\t// An id whose entry is gone is dropped; its value stays in the column.\n\t\t\tif (group && !groups.includes(group)) groups.push(group);\n\t\t}\n\t\tconst selected = backfill.maxChildren === null ? groups : groups.slice(0, backfill.maxChildren);\n\t\tfor (const [sortOrder, childGroup] of selected.entries()) {\n\t\t\trows.push({ parentGroup, childGroup, sortOrder });\n\t\t}\n\t}\n\n\t// This runs inside the transaction that binds the field, so an editor binding\n\t// a field on a large legacy collection waits for it: batch rather than paying\n\t// a round trip per edge.\n\tfor (const batch of chunks(rows, REFERENCE_INSERT_BATCH_SIZE)) {\n\t\tconst values = batch.map(\n\t\t\t(row) =>\n\t\t\t\tsql`(${ulid()}, ${backfill.relationId}, ${row.parentGroup}, ${row.childGroup}, ${row.sortOrder}, ${now})`,\n\t\t);\n\t\t// oxlint-disable-next-line no-await-in-loop -- one statement per bind-parameter batch\n\t\tawait sql`\n\t\t\tINSERT INTO ${sql.ref(\"_emdash_content_references\")}\n\t\t\t\t(id, relation_id, parent_group, child_group, sort_order, created_at)\n\t\t\tVALUES ${sql.join(values)}\n\t\t\tON CONFLICT DO NOTHING\n\t\t`.execute(db);\n\t}\n}\n","/**\n * Schema/collection management handlers\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { backfillReferenceEdges } from \"../../database/reference-backfill.js\";\nimport { RelationRepository, type Relation } from \"../../database/repositories/relation.js\";\nimport { withTransaction } from \"../../database/transaction.js\";\nimport type { Database } from \"../../database/types.js\";\nimport {\n\tinvalidateCollectionCache,\n\tinvalidateSchemaObjectCache,\n} from \"../../object-cache/index.js\";\nimport {\n\tSchemaRegistry,\n\tSchemaError,\n\tinvalidateSchemaCache,\n\ttype Collection,\n\ttype Field,\n\ttype CreateCollectionInput,\n\ttype UpdateCollectionInput,\n\ttype CreateFieldInput,\n\ttype UpdateFieldInput,\n\ttype CollectionWithFields,\n\texpandCollectionBlockFields,\n} from \"../../schema/index.js\";\nimport type { ApiResult } from \"../types.js\";\nimport { fieldsBoundToRelation, handleRelationDelete } from \"./relations.js\";\n\n/** Maximum attempts to allocate a unique relation slug for a new reference\n * field: the base `${collection}_${field}` slug, then `_2` through `_5`. */\nconst RELATION_NAME_MAX_ATTEMPTS = 5;\n\n/** True for SQLite UNIQUE / Postgres unique_violation messages — mirrors the\n * fingerprint used in the relations API handler. */\nfunction isUniqueViolation(error: unknown): boolean {\n\tconst message = error instanceof Error ? error.message.toLowerCase() : \"\";\n\treturn message.includes(\"unique constraint failed\") || message.includes(\"duplicate key\");\n}\n\n/**\n * Create the relation definition backing a new reference field, retrying\n * with a numeric suffix on a name collision. Runs inside the caller's\n * transaction so the relation and the field row it backs commit or roll\n * back together.\n */\nexport async function createFieldRelation(\n\ttrx: Kysely<Database>,\n\tcollectionSlug: string,\n\tfieldSlug: string,\n\tfieldLabel: string,\n\ttargetCollection: string,\n\t/** How many entries the new field may hold. `null` is unlimited. */\n\tmaxChildrenPerParent: number | null = null,\n): Promise<Relation> {\n\tconst registry = new SchemaRegistry(trx);\n\tconst relations = new RelationRepository(trx);\n\n\tconst parent = await registry.getCollection(collectionSlug);\n\tif (!parent) {\n\t\tthrow new SchemaError(`Collection \"${collectionSlug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t}\n\n\tif (!(await registry.getCollection(targetCollection))) {\n\t\tthrow new SchemaError(\n\t\t\t`Target collection \"${targetCollection}\" not found`,\n\t\t\t\"COLLECTION_NOT_FOUND\",\n\t\t);\n\t}\n\n\tconst baseSlug = `${collectionSlug}_${fieldSlug}`.slice(0, 63);\n\tfor (let attempt = 0; attempt < RELATION_NAME_MAX_ATTEMPTS; attempt++) {\n\t\tconst suffix = attempt === 0 ? \"\" : `_${attempt + 1}`;\n\t\tconst slug = attempt === 0 ? baseSlug : `${baseSlug.slice(0, 63 - suffix.length)}${suffix}`;\n\t\ttry {\n\t\t\treturn await relations.create({\n\t\t\t\tslug,\n\t\t\t\tparentCollection: collectionSlug,\n\t\t\t\tchildCollection: targetCollection,\n\t\t\t\tparentLabel: parent.label,\n\t\t\t\tparentLabelSingular: parent.labelSingular ?? null,\n\t\t\t\tchildLabel: fieldLabel,\n\t\t\t\tmaxChildrenPerParent,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst isLastAttempt = attempt === RELATION_NAME_MAX_ATTEMPTS - 1;\n\t\t\tif (isLastAttempt || !isUniqueViolation(error)) throw error;\n\t\t}\n\t}\n\tthrow new SchemaError(\"Could not allocate a unique relation name\", \"RELATION_NAME_CONFLICT\");\n}\n\n/**\n * Every cache a field change can stale.\n *\n * The schema object-cache namespace is bumped here rather than only by the\n * collection routes: the render path's reference field map lives in that\n * namespace, so a field created, bound, relabelled or deleted would otherwise\n * keep resolving against the shape the collection used to have.\n */\nfunction invalidateFieldCaches(collectionSlug: string): void {\n\tinvalidateCollectionCache(collectionSlug);\n\tinvalidateSchemaCache(collectionSlug);\n\tinvalidateSchemaObjectCache();\n}\n\n/**\n * Bind a reference field that has no relation to one, and copy the selection its\n * column holds in as edges.\n *\n * The column is left in place but stops being written, so the field also stops\n * being `indexed` and `searchable`: an index over a frozen column would answer\n * content-list filters and searches from values that no longer change. Clearing\n * both here drops the field index and re-syncs FTS through `updateField`.\n */\nexport async function bindReferenceField(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\texisting: Field,\n\tinput: UpdateFieldInput,\n\ttargetCollection: string,\n): Promise<Field> {\n\tconst label = input.label ?? existing.label;\n\tconst maxChildren = input.validation?.multiple ? null : 1;\n\n\treturn withTransaction(db, async (trx) => {\n\t\tconst relation = await createFieldRelation(\n\t\t\ttrx,\n\t\t\tcollectionSlug,\n\t\t\texisting.slug,\n\t\t\tlabel,\n\t\t\ttargetCollection,\n\t\t\tmaxChildren,\n\t\t);\n\t\tconst registry = new SchemaRegistry(trx);\n\t\tconst updated = await registry.updateField(collectionSlug, existing.slug, {\n\t\t\t...input,\n\t\t\tindexed: false,\n\t\t\tsearchable: false,\n\t\t\tvalidation: {\n\t\t\t\t...input.validation,\n\t\t\t\trelation: relation.slug,\n\t\t\t\trelationSide: \"parent\",\n\t\t\t\ttargetCollection,\n\t\t\t},\n\t\t});\n\n\t\tawait backfillReferenceEdges(trx, {\n\t\t\tparentCollection: collectionSlug,\n\t\t\tchildCollection: targetCollection,\n\t\t\tfieldSlug: existing.slug,\n\t\t\trelationId: relation.id,\n\t\t\tmaxChildren,\n\t\t});\n\n\t\treturn updated;\n\t});\n}\n\nexport interface CollectionListResponse {\n\titems: Collection[];\n}\n\nexport interface CollectionResponse {\n\titem: Collection;\n}\n\nexport interface CollectionWithFieldsResponse {\n\titem: CollectionWithFields;\n}\n\nexport interface FieldListResponse {\n\titems: Field[];\n}\n\nexport interface FieldResponse {\n\titem: Field;\n}\n\n/**\n * List all collections\n */\nexport async function handleSchemaCollectionList(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<CollectionListResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst items = await registry.listCollections();\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { items },\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_LIST_ERROR\",\n\t\t\t\tmessage: \"Failed to list collections\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Get a collection by slug\n */\nexport async function handleSchemaCollectionGet(\n\tdb: Kysely<Database>,\n\tslug: string,\n\toptions?: { includeFields?: boolean },\n): Promise<ApiResult<CollectionResponse | CollectionWithFieldsResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\n\t\tif (options?.includeFields) {\n\t\t\tconst stored = await registry.getCollectionWithFields(slug);\n\t\t\tconst item = stored ? await expandCollectionBlockFields(db, stored) : null;\n\t\t\tif (!item) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tmessage: `Collection not found: ${slug}`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { item },\n\t\t\t};\n\t\t}\n\n\t\tconst item = await registry.getCollection(slug);\n\t\tif (!item) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\tmessage: `Collection not found: ${slug}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: error.code, message: error.message, details: error.details },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_GET_ERROR\",\n\t\t\t\tmessage: \"Failed to get collection\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Create a collection\n */\nexport async function handleSchemaCollectionCreate(\n\tdb: Kysely<Database>,\n\tinput: CreateCollectionInput,\n): Promise<ApiResult<CollectionResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst item = await registry.createCollection(input);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconsole.error(\"[emdash] Failed to create collection:\", error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_CREATE_ERROR\",\n\t\t\t\tmessage: \"Failed to create collection\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Update a collection\n */\nexport async function handleSchemaCollectionUpdate(\n\tdb: Kysely<Database>,\n\tslug: string,\n\tinput: UpdateCollectionInput,\n): Promise<ApiResult<CollectionResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst item = await registry.updateCollection(slug, input);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_UPDATE_ERROR\",\n\t\t\t\tmessage: \"Failed to update collection\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Delete a collection\n */\nexport async function handleSchemaCollectionDelete(\n\tdb: Kysely<Database>,\n\tslug: string,\n\toptions?: { force?: boolean },\n): Promise<ApiResult<{ success: boolean }>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\n\t\t// Nothing below can be undone on D1, so a delete that will be refused has\n\t\t// to be refused before the first relation goes.\n\t\tawait registry.assertCollectionDeletable(slug, options);\n\n\t\t// A relation with this collection on either end cannot outlive it: its\n\t\t// edges point at content that is about to be dropped, and the reference\n\t\t// fields viewing it — including ones on the *other* collection — would be\n\t\t// left addressing a collection that no longer exists. The admin lists both\n\t\t// before confirming. Relations go first, so an interrupted delete leaves a\n\t\t// collection with fewer relations rather than a dropped table with\n\t\t// relations still pointing at it.\n\t\tconst relations = new RelationRepository(db);\n\t\tfor (const relation of await relations.findForCollection(slug)) {\n\t\t\tconst removed = await handleRelationDelete(db, relation.id);\n\t\t\tif (!removed.success) return removed;\n\t\t}\n\n\t\tawait registry.deleteCollection(slug, options);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { success: true },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_DELETE_ERROR\",\n\t\t\t\tmessage: \"Failed to delete collection\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * List fields for a collection\n */\nexport async function handleSchemaFieldList(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n): Promise<ApiResult<FieldListResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst stored = await registry.getCollectionWithFields(collectionSlug);\n\n\t\tif (!stored) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\tmessage: `Collection not found: ${collectionSlug}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst items = (await expandCollectionBlockFields(db, stored)).fields;\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { items },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: error.code, message: error.message, details: error.details },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_LIST_ERROR\",\n\t\t\t\tmessage: \"Failed to list fields\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Get a field\n */\nexport async function handleSchemaFieldGet(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tfieldSlug: string,\n): Promise<ApiResult<FieldResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst collection = await registry.getCollectionWithFields(collectionSlug);\n\t\tconst item = collection\n\t\t\t? (await expandCollectionBlockFields(db, collection)).fields.find(\n\t\t\t\t\t(field) => field.slug === fieldSlug,\n\t\t\t\t)\n\t\t\t: null;\n\n\t\tif (!item) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\tmessage: `Field not found: ${fieldSlug} in collection ${collectionSlug}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: error.code, message: error.message, details: error.details },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_GET_ERROR\",\n\t\t\t\tmessage: \"Failed to get field\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Resolve which end of `relation` a field on `collectionSlug` sits on.\n *\n * The side is only a choice when both ends are the same collection — a\n * self-referential relation such as related posts. Anywhere else the matching\n * end decides it, and an explicit side that disagrees is a client error rather\n * than something to silently override.\n */\nfunction resolveBindingSide(\n\trelation: Relation,\n\tcollectionSlug: string,\n\trequested: \"parent\" | \"child\" | undefined,\n): { side: \"parent\" | \"child\"; targetCollection: string } | { error: string } {\n\tconst isParent = relation.parentCollection === collectionSlug;\n\tconst isChild = relation.childCollection === collectionSlug;\n\n\tif (!isParent && !isChild) {\n\t\treturn {\n\t\t\terror: `Relation '${relation.slug}' does not touch collection '${collectionSlug}'`,\n\t\t};\n\t}\n\n\tif (isParent && isChild) {\n\t\tconst side = requested ?? \"parent\";\n\t\treturn {\n\t\t\tside,\n\t\t\ttargetCollection: side === \"parent\" ? relation.childCollection : relation.parentCollection,\n\t\t};\n\t}\n\n\tconst side = isParent ? \"parent\" : \"child\";\n\tif (requested && requested !== side) {\n\t\treturn {\n\t\t\terror: `Collection '${collectionSlug}' is the ${side} of relation '${relation.slug}'`,\n\t\t};\n\t}\n\n\treturn {\n\t\tside,\n\t\ttargetCollection: isParent ? relation.childCollection : relation.parentCollection,\n\t};\n}\n\n/**\n * Create a reference field that views an existing relation.\n *\n * Only one field may view a relation from a given end: two pickers writing the\n * same link set have no defined merge, and the second would silently overwrite\n * the first on every save.\n */\nasync function createBoundReferenceField(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tinput: CreateFieldInput,\n\trelationSlug: string,\n): Promise<ApiResult<FieldResponse>> {\n\tconst relation = await new RelationRepository(db).findBySlug(relationSlug);\n\tif (!relation) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND\", message: `Relation '${relationSlug}' not found` },\n\t\t};\n\t}\n\n\tconst resolved = resolveBindingSide(relation, collectionSlug, input.validation?.relationSide);\n\tif (\"error\" in resolved) {\n\t\treturn { success: false, error: { code: \"VALIDATION_ERROR\", message: resolved.error } };\n\t}\n\n\tconst bound = await fieldsBoundToRelation(db, relation.slug);\n\tconst taken = bound.find((field) => field.side === resolved.side);\n\tif (taken) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\tmessage: `Relation '${relation.slug}' is already picked from by ${taken.collectionSlug}.${taken.fieldSlug}`,\n\t\t\t},\n\t\t};\n\t}\n\n\tconst item = await new SchemaRegistry(db).createField(collectionSlug, {\n\t\t...input,\n\t\tvalidation: {\n\t\t\t...input.validation,\n\t\t\trelation: relation.slug,\n\t\t\trelationSide: resolved.side,\n\t\t\ttargetCollection: resolved.targetCollection,\n\t\t},\n\t});\n\n\tinvalidateFieldCaches(collectionSlug);\n\n\treturn { success: true, data: { item } };\n}\n\n/**\n * Create a field\n */\nexport async function handleSchemaFieldCreate(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tinput: CreateFieldInput,\n): Promise<ApiResult<FieldResponse>> {\n\ttry {\n\t\tif (input.type === \"reference\" && input.validation?.relation) {\n\t\t\treturn await createBoundReferenceField(db, collectionSlug, input, input.validation.relation);\n\t\t}\n\n\t\tif (input.type === \"reference\") {\n\t\t\tconst targetCollection = input.validation?.targetCollection;\n\t\t\tif (!targetCollection) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\tmessage: \"Reference field requires a target collection\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// The relation def and the field row it backs must commit or roll\n\t\t\t// back together — a field without its relation (or vice versa) is\n\t\t\t// an inconsistent reference field.\n\t\t\tconst item = await withTransaction(db, async (trx) => {\n\t\t\t\t// A single-reference field is a one-to-many relation: the limit is the\n\t\t\t\t// relation's, so binding its other end later sees the same rule.\n\t\t\t\tconst relation = await createFieldRelation(\n\t\t\t\t\ttrx,\n\t\t\t\t\tcollectionSlug,\n\t\t\t\t\tinput.slug,\n\t\t\t\t\tinput.label,\n\t\t\t\t\ttargetCollection,\n\t\t\t\t\tinput.validation?.multiple ? null : 1,\n\t\t\t\t);\n\t\t\t\tconst registry = new SchemaRegistry(trx);\n\t\t\t\treturn registry.createField(collectionSlug, {\n\t\t\t\t\t...input,\n\t\t\t\t\tvalidation: {\n\t\t\t\t\t\t...input.validation,\n\t\t\t\t\t\trelation: relation.slug,\n\t\t\t\t\t\trelationSide: \"parent\" as const,\n\t\t\t\t\t\ttargetCollection,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// Content snapshots embed field values; a column change invalidates them.\n\t\t\tinvalidateFieldCaches(collectionSlug);\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { item },\n\t\t\t};\n\t\t}\n\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst item = await registry.createField(collectionSlug, input);\n\n\t\t// Content snapshots embed field values; a column change invalidates them.\n\t\tinvalidateFieldCaches(collectionSlug);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_CREATE_ERROR\",\n\t\t\t\tmessage: \"Failed to create field\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Update a field\n */\nexport async function handleSchemaFieldUpdate(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tfieldSlug: string,\n\tinput: UpdateFieldInput,\n): Promise<ApiResult<FieldResponse>> {\n\ttry {\n\t\tconst lookupRegistry = new SchemaRegistry(db);\n\t\tconst existing = await lookupRegistry.getField(collectionSlug, fieldSlug);\n\t\tconst relationSlug = existing?.type === \"reference\" ? existing.validation?.relation : undefined;\n\t\tconst relationSide = existing?.validation?.relationSide;\n\n\t\tif (existing && relationSlug) {\n\t\t\t// The relation's childCollection is immutable — a reference field's\n\t\t\t// target collection can't change after the relation is wired up.\n\t\t\tconst nextTargetCollection = input.validation?.targetCollection;\n\t\t\tif (\n\t\t\t\tnextTargetCollection !== undefined &&\n\t\t\t\tnextTargetCollection !== existing.validation?.targetCollection\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\tmessage: \"Cannot change the target collection of an existing reference field\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// `relation` and `targetCollection` are immutable identity for a wired\n\t\t\t// reference field. An update that sends `validation: null` or a partial\n\t\t\t// validation object omitting these keys must not be allowed to clear\n\t\t\t// them -- registry.updateField() writes whatever is passed verbatim,\n\t\t\t// which would otherwise orphan the relation row and its edges.\n\t\t\tconst updateInput =\n\t\t\t\tinput.validation !== undefined\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...input,\n\t\t\t\t\t\t\tvalidation: {\n\t\t\t\t\t\t\t\t...input.validation,\n\t\t\t\t\t\t\t\trelation: existing.validation?.relation,\n\t\t\t\t\t\t\t\trelationSide: existing.validation?.relationSide,\n\t\t\t\t\t\t\t\ttargetCollection: existing.validation?.targetCollection,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: input;\n\n\t\t\tconst item = await withTransaction(db, async (trx) => {\n\t\t\t\tconst registry = new SchemaRegistry(trx);\n\t\t\t\tconst updated = await registry.updateField(collectionSlug, fieldSlug, updateInput);\n\n\t\t\t\tif (input.label !== undefined && input.label !== existing.label) {\n\t\t\t\t\tconst relations = new RelationRepository(trx);\n\t\t\t\t\tconst relation = await relations.findBySlug(relationSlug);\n\t\t\t\t\t// The field's label is the role name for the side it binds, so\n\t\t\t\t\t// renaming the field renames that role and leaves the other alone.\n\t\t\t\t\tif (relation) {\n\t\t\t\t\t\tawait relations.update(\n\t\t\t\t\t\t\trelation.id,\n\t\t\t\t\t\t\trelationSide === \"child\" ? { parentLabel: input.label } : { childLabel: input.label },\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn updated;\n\t\t\t});\n\n\t\t\tinvalidateFieldCaches(collectionSlug);\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: { item },\n\t\t\t};\n\t\t}\n\n\t\t// Giving an unbound reference field a target collection binds it: a field\n\t\t// created before relations existed, or one whose target could not be\n\t\t// resolved on upgrade, becomes a picker here rather than needing to be\n\t\t// deleted and recreated.\n\t\tconst bindTarget = existing?.type === \"reference\" ? input.validation?.targetCollection : null;\n\t\tif (existing && bindTarget) {\n\t\t\tconst item = await bindReferenceField(db, collectionSlug, existing, input, bindTarget);\n\t\t\tinvalidateFieldCaches(collectionSlug);\n\t\t\treturn { success: true, data: { item } };\n\t\t}\n\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst item = await registry.updateField(collectionSlug, fieldSlug, input);\n\n\t\tinvalidateFieldCaches(collectionSlug);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_UPDATE_ERROR\",\n\t\t\t\tmessage: \"Failed to update field\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Delete a field\n */\n/**\n * Delete a field.\n *\n * For a reference field, `deleteRelation` also takes the relation, its edges,\n * and the field bound to its other side. It is opt-in on the wire and checked\n * by default in the admin's confirm dialog, which enumerates what goes first.\n */\nexport async function handleSchemaFieldDelete(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tfieldSlug: string,\n\toptions?: { deleteRelation?: boolean },\n): Promise<ApiResult<{ success: boolean }>> {\n\ttry {\n\t\tconst lookupRegistry = new SchemaRegistry(db);\n\t\tconst existing = await lookupRegistry.getField(collectionSlug, fieldSlug);\n\t\tconst relationSlug = existing?.type === \"reference\" ? existing.validation?.relation : undefined;\n\n\t\tif (relationSlug && options?.deleteRelation) {\n\t\t\t// Taking the relation takes its edges and the field bound to its other\n\t\t\t// side, so route through the shared cascade rather than deleting the\n\t\t\t// field here and the relation separately.\n\t\t\tconst relations = new RelationRepository(db);\n\t\t\tconst relation = await relations.findBySlug(relationSlug);\n\t\t\tif (relation) {\n\t\t\t\tconst result = await handleRelationDelete(db, relation.id);\n\t\t\t\tif (!result.success) return result;\n\t\t\t\tinvalidateFieldCaches(collectionSlug);\n\t\t\t\treturn { success: true, data: { success: true } };\n\t\t\t}\n\t\t}\n\n\t\tconst registry = new SchemaRegistry(db);\n\t\tawait registry.deleteField(collectionSlug, fieldSlug);\n\n\t\tinvalidateFieldCaches(collectionSlug);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { success: true },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_DELETE_ERROR\",\n\t\t\t\tmessage: \"Failed to delete field\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Reorder collections in the admin sidebar\n */\nexport async function handleSchemaCollectionReorder(\n\tdb: Kysely<Database>,\n\tslugs: string[],\n): Promise<ApiResult<{ success: boolean }>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tawait registry.reorderCollections(slugs);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { success: true },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconsole.error(\"[emdash] Failed to reorder collections:\", error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_COLLECTION_REORDER_ERROR\",\n\t\t\t\tmessage: \"Failed to reorder collections\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Reorder fields\n */\nexport async function handleSchemaFieldReorder(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tfieldSlugs: string[],\n): Promise<ApiResult<{ success: boolean }>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tawait registry.reorderFields(collectionSlug, fieldSlugs);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { success: true },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"SCHEMA_FIELD_REORDER_ERROR\",\n\t\t\t\tmessage: \"Failed to reorder fields\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n// ============================================\n// Orphaned Table Discovery\n// ============================================\n\nexport interface OrphanedTable {\n\tslug: string;\n\ttableName: string;\n\trowCount: number;\n}\n\nexport interface OrphanedTableListResponse {\n\titems: OrphanedTable[];\n}\n\n/**\n * List orphaned content tables\n */\nexport async function handleOrphanedTableList(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<OrphanedTableListResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst items = await registry.discoverOrphanedTables();\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { items },\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"[emdash] Failed to list orphaned tables:\", error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"ORPHAN_LIST_ERROR\",\n\t\t\t\tmessage: \"Failed to list orphaned tables\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Register an orphaned table as a collection\n */\nexport async function handleOrphanedTableRegister(\n\tdb: Kysely<Database>,\n\tslug: string,\n\toptions?: {\n\t\tlabel?: string;\n\t\tlabelSingular?: string;\n\t\tdescription?: string;\n\t},\n): Promise<ApiResult<CollectionResponse>> {\n\ttry {\n\t\tconst registry = new SchemaRegistry(db);\n\t\tconst item = await registry.registerOrphanedTable(slug, options);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { item },\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t\tdetails: error.details,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"ORPHAN_REGISTER_ERROR\",\n\t\t\t\tmessage: \"Failed to register orphaned table\",\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { t as apiError } from "./error-BfsNNrIE.mjs";
|
|
2
|
+
import { a as hasScope } from "./api-tokens-FaG1zPsj.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/auth/scopes.ts
|
|
5
|
+
/**
|
|
6
|
+
* Scope enforcement for API token authentication.
|
|
7
|
+
*
|
|
8
|
+
* Routes call `requireScope(locals, "content:write")` alongside role checks.
|
|
9
|
+
* Session-authenticated requests have no scope restrictions (implicit full access).
|
|
10
|
+
* Token-authenticated requests must have the required scope (or "admin").
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Check if the request has a required scope.
|
|
14
|
+
* Returns a 403 Response if the scope is missing, or null if OK.
|
|
15
|
+
*
|
|
16
|
+
* For session-authenticated users (no tokenScopes), always returns null
|
|
17
|
+
* since session auth has implicit full scope.
|
|
18
|
+
*/
|
|
19
|
+
function requireScope(locals, scope) {
|
|
20
|
+
if (!locals.tokenScopes) return null;
|
|
21
|
+
if (hasScope(locals.tokenScopes, scope)) return null;
|
|
22
|
+
return apiError("INSUFFICIENT_SCOPE", `Token lacks required scope: ${scope}`, 403);
|
|
23
|
+
}
|
|
24
|
+
/** Like {@link requireScope}, but satisfied by any of `scopes`. */
|
|
25
|
+
function requireAnyScope(locals, scopes) {
|
|
26
|
+
const tokenScopes = locals.tokenScopes;
|
|
27
|
+
if (!tokenScopes) return null;
|
|
28
|
+
if (scopes.some((scope) => hasScope(tokenScopes, scope))) return null;
|
|
29
|
+
return apiError("INSUFFICIENT_SCOPE", `Token lacks required scope: ${scopes.join(" or ")}`, 403);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { requireScope as n, requireAnyScope as t };
|
|
34
|
+
//# sourceMappingURL=scopes-BqPOKoKf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes-BqPOKoKf.mjs","names":[],"sources":["../src/auth/scopes.ts"],"sourcesContent":["/**\n * Scope enforcement for API token authentication.\n *\n * Routes call `requireScope(locals, \"content:write\")` alongside role checks.\n * Session-authenticated requests have no scope restrictions (implicit full access).\n * Token-authenticated requests must have the required scope (or \"admin\").\n */\n\nimport { apiError } from \"#api/error.js\";\n\nimport { hasScope } from \"./api-tokens.js\";\n\n/**\n * Check if the request has a required scope.\n * Returns a 403 Response if the scope is missing, or null if OK.\n *\n * For session-authenticated users (no tokenScopes), always returns null\n * since session auth has implicit full scope.\n */\nexport function requireScope(locals: { tokenScopes?: string[] }, scope: string): Response | null {\n\t// Session auth = no scope restrictions\n\tif (!locals.tokenScopes) return null;\n\n\tif (hasScope(locals.tokenScopes, scope)) return null;\n\n\treturn apiError(\"INSUFFICIENT_SCOPE\", `Token lacks required scope: ${scope}`, 403);\n}\n\n/** Like {@link requireScope}, but satisfied by any of `scopes`. */\nexport function requireAnyScope(\n\tlocals: { tokenScopes?: string[] },\n\tscopes: readonly string[],\n): Response | null {\n\tconst tokenScopes = locals.tokenScopes;\n\tif (!tokenScopes) return null;\n\tif (scopes.some((scope) => hasScope(tokenScopes, scope))) return null;\n\treturn apiError(\"INSUFFICIENT_SCOPE\", `Token lacks required scope: ${scopes.join(\" or \")}`, 403);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,SAAgB,aAAa,QAAoC,OAAgC;AAEhG,KAAI,CAAC,OAAO,YAAa,QAAO;AAEhC,KAAI,SAAS,OAAO,aAAa,MAAM,CAAE,QAAO;AAEhD,QAAO,SAAS,sBAAsB,+BAA+B,SAAS,IAAI;;;AAInF,SAAgB,gBACf,QACA,QACkB;CAClB,MAAM,cAAc,OAAO;AAC3B,KAAI,CAAC,YAAa,QAAO;AACzB,KAAI,OAAO,MAAM,UAAU,SAAS,aAAa,MAAM,CAAC,CAAE,QAAO;AACjE,QAAO,SAAS,sBAAsB,+BAA+B,OAAO,KAAK,OAAO,IAAI,IAAI"}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { u as __exportAll } from "./runner-B3eyB9Gb.mjs";
|
|
2
|
+
import { t as validateIdentifier } from "./validate-DANX1-Qi.mjs";
|
|
3
|
+
import { o as resolveConfiguredLocale } from "./config-CvmjJcVw.mjs";
|
|
4
|
+
import { c as encodeCursor, i as InvalidCursorError, s as decodeCursor } from "./types-aOOxRSx6.mjs";
|
|
5
|
+
import { t as FTSManager } from "./fts-manager-CCaZTp8y.mjs";
|
|
6
|
+
import { s as getDb } from "./loader-CrRPfkHS.mjs";
|
|
7
|
+
import { sql } from "kysely";
|
|
8
|
+
import { toPlainText } from "@portabletext/toolkit";
|
|
9
|
+
|
|
10
|
+
//#region src/search/query.ts
|
|
11
|
+
/**
|
|
12
|
+
* Marker stored in the `id` slot of a search pagination cursor.
|
|
13
|
+
*
|
|
14
|
+
* Search results are merged from per-collection FTS queries and re-sorted by
|
|
15
|
+
* score, so there is no single stable keyset column to encode (the way
|
|
16
|
+
* `getEmDashCollection` encodes `(orderValue, id)`). We page over the merged,
|
|
17
|
+
* score-sorted set by offset instead, carried as the cursor's `orderValue`.
|
|
18
|
+
* Reusing `encodeCursor`/`decodeCursor` keeps the opaque base64-JSON shape and
|
|
19
|
+
* the `InvalidCursorError` handling consistent with the rest of the API.
|
|
20
|
+
*/
|
|
21
|
+
const SEARCH_CURSOR_MARKER = "search";
|
|
22
|
+
/** Encode the next-page offset into an opaque search cursor. */
|
|
23
|
+
function encodeSearchCursor(offset) {
|
|
24
|
+
return encodeCursor(String(offset), SEARCH_CURSOR_MARKER);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Decode a search cursor back to its offset. Throws `InvalidCursorError` for a
|
|
28
|
+
* malformed cursor or one that doesn't carry a non-negative integer offset, so
|
|
29
|
+
* a client pagination bug surfaces immediately rather than silently restarting
|
|
30
|
+
* from the first page.
|
|
31
|
+
*/
|
|
32
|
+
/** Upper bound on a decoded search offset, to cap the per-collection row fetch a forged cursor can trigger. */
|
|
33
|
+
const MAX_SEARCH_OFFSET = 1e4;
|
|
34
|
+
function decodeSearchOffset(cursor) {
|
|
35
|
+
const { orderValue, id } = decodeCursor(cursor);
|
|
36
|
+
if (id !== SEARCH_CURSOR_MARKER) throw new InvalidCursorError(cursor);
|
|
37
|
+
const offset = Number(orderValue);
|
|
38
|
+
if (!Number.isInteger(offset) || offset < 0 || offset > MAX_SEARCH_OFFSET) throw new InvalidCursorError(cursor);
|
|
39
|
+
return offset;
|
|
40
|
+
}
|
|
41
|
+
/** Pattern to split on whitespace for query term extraction */
|
|
42
|
+
const WHITESPACE_SPLIT_PATTERN = /\s+/;
|
|
43
|
+
const FTS_OPERATORS_PATTERN = /\b(AND|OR|NOT|NEAR)\b/i;
|
|
44
|
+
const DOUBLE_QUOTE_PATTERN = /"/g;
|
|
45
|
+
/**
|
|
46
|
+
* Detect FTS5 query syntax errors. Match specifically on the SQLite FTS5
|
|
47
|
+
* error fingerprints rather than a broad "fts5" / "syntax error" filter
|
|
48
|
+
* (which would also swallow internal table-corruption errors). The two
|
|
49
|
+
* fingerprints we care about are:
|
|
50
|
+
*
|
|
51
|
+
* - "fts5: syntax error near …" — unbalanced quotes, stray operators,
|
|
52
|
+
* other malformed user input
|
|
53
|
+
* - "unknown special query: …" — bare special tokens like `^*` that
|
|
54
|
+
* parse but don't resolve to a real FTS5 directive
|
|
55
|
+
*/
|
|
56
|
+
function isFts5SyntaxError(error) {
|
|
57
|
+
if (!(error instanceof Error)) return false;
|
|
58
|
+
const message = error.message.toLowerCase();
|
|
59
|
+
return message.includes("fts5: syntax error") || message.includes("unknown special query");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Search across multiple collections
|
|
63
|
+
*
|
|
64
|
+
* Public API that auto-injects the database.
|
|
65
|
+
*
|
|
66
|
+
* @param query - Search query (FTS5 syntax supported)
|
|
67
|
+
* @param options - Search options
|
|
68
|
+
* @returns Search results with pagination
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { search } from "emdash";
|
|
73
|
+
*
|
|
74
|
+
* const results = await search("hello world", {
|
|
75
|
+
* collections: ["posts", "pages"],
|
|
76
|
+
* limit: 20
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
async function search(query, options = {}) {
|
|
81
|
+
return searchWithDb(await getDb(), query, options);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Search across multiple collections (with explicit db)
|
|
85
|
+
*
|
|
86
|
+
* @internal Use `search()` in templates. This variant is for admin routes
|
|
87
|
+
* that already have a database handle.
|
|
88
|
+
*
|
|
89
|
+
* @param db - Kysely database instance
|
|
90
|
+
* @param query - Search query (FTS5 syntax supported)
|
|
91
|
+
* @param options - Search options
|
|
92
|
+
* @returns Search results with pagination
|
|
93
|
+
*/
|
|
94
|
+
async function searchWithDb(db, query, options = {}) {
|
|
95
|
+
const ftsManager = new FTSManager(db);
|
|
96
|
+
const limit = options.limit ?? 20;
|
|
97
|
+
const status = options.status ?? "published";
|
|
98
|
+
const offset = options.cursor ? decodeSearchOffset(options.cursor) : 0;
|
|
99
|
+
let collections = options.collections;
|
|
100
|
+
if (!collections || collections.length === 0) collections = await getSearchableCollections(db);
|
|
101
|
+
if (collections.length === 0) return { items: [] };
|
|
102
|
+
const perCollectionLimit = offset + limit + 1;
|
|
103
|
+
const allResults = [];
|
|
104
|
+
const titleColumns = await ftsManager.getCollectionsWithTitleColumn(collections);
|
|
105
|
+
for (const collection of collections) {
|
|
106
|
+
const config = await ftsManager.getSearchConfig(collection);
|
|
107
|
+
if (!config?.enabled) continue;
|
|
108
|
+
const collectionResults = await searchSingleCollection(db, collection, query, {
|
|
109
|
+
status,
|
|
110
|
+
locale: options.locale,
|
|
111
|
+
limit: perCollectionLimit,
|
|
112
|
+
scope: options.scope
|
|
113
|
+
}, config.weights, titleColumns.has(collection), config.titleField);
|
|
114
|
+
allResults.push(...collectionResults);
|
|
115
|
+
}
|
|
116
|
+
allResults.sort((a, b) => b.score - a.score);
|
|
117
|
+
return {
|
|
118
|
+
items: allResults.slice(offset, offset + limit),
|
|
119
|
+
nextCursor: allResults.length > offset + limit ? encodeSearchCursor(offset + limit) : void 0
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Search within a single collection
|
|
124
|
+
*
|
|
125
|
+
* @param db - Kysely database instance
|
|
126
|
+
* @param collection - Collection slug
|
|
127
|
+
* @param query - Search query (FTS5 syntax supported)
|
|
128
|
+
* @param options - Search options
|
|
129
|
+
* @returns Search results with pagination
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const results = await searchCollection(db, "posts", "hello world", {
|
|
134
|
+
* limit: 10
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
async function searchCollection(db, collection, query, options = {}) {
|
|
139
|
+
const config = await new FTSManager(db).getSearchConfig(collection);
|
|
140
|
+
if (!config?.enabled) return { items: [] };
|
|
141
|
+
const limit = options.limit ?? 20;
|
|
142
|
+
const offset = options.cursor ? decodeSearchOffset(options.cursor) : 0;
|
|
143
|
+
const fetched = await searchSingleCollection(db, collection, query, {
|
|
144
|
+
status: options.status,
|
|
145
|
+
locale: options.locale,
|
|
146
|
+
limit: offset + limit + 1,
|
|
147
|
+
scope: options.scope
|
|
148
|
+
}, config.weights, void 0, config.titleField);
|
|
149
|
+
return {
|
|
150
|
+
items: fetched.slice(offset, offset + limit),
|
|
151
|
+
nextCursor: fetched.length > offset + limit ? encodeSearchCursor(offset + limit) : void 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Internal function to search a single collection
|
|
156
|
+
*/
|
|
157
|
+
async function searchSingleCollection(db, collection, query, options, weights, hasTitle, titleField) {
|
|
158
|
+
validateIdentifier(collection, "collection slug");
|
|
159
|
+
const ftsManager = new FTSManager(db);
|
|
160
|
+
const ftsTable = ftsManager.getFtsTableName(collection);
|
|
161
|
+
const contentTable = ftsManager.getContentTableName(collection);
|
|
162
|
+
const limit = options.limit ?? 20;
|
|
163
|
+
const status = options.status ?? "published";
|
|
164
|
+
const locale = options.locale ? resolveConfiguredLocale(options.locale) : void 0;
|
|
165
|
+
if (!await ftsManager.ftsTableExists(collection)) return [];
|
|
166
|
+
const escapedQuery = escapeQuery(query);
|
|
167
|
+
if (!escapedQuery) return [];
|
|
168
|
+
const searchableFields = await ftsManager.getSearchableFields(collection);
|
|
169
|
+
let matchQuery = escapedQuery;
|
|
170
|
+
if (options.scope === "title") {
|
|
171
|
+
const titleColumn = titleField && searchableFields.includes(titleField) ? titleField : searchableFields.includes("title") ? "title" : void 0;
|
|
172
|
+
if (!titleColumn) return [];
|
|
173
|
+
validateIdentifier(titleColumn, "title field");
|
|
174
|
+
matchQuery = `${titleColumn} : (${escapeQuery(query, false)})`;
|
|
175
|
+
}
|
|
176
|
+
let titleExpr;
|
|
177
|
+
if (titleField) {
|
|
178
|
+
validateIdentifier(titleField, "title field");
|
|
179
|
+
titleExpr = sql`c.${sql.ref(titleField)}`;
|
|
180
|
+
} else titleExpr = hasTitle ?? await ftsManager.hasTitleColumn(collection) ? sql`c.title` : sql`NULL`;
|
|
181
|
+
let bm25Args = "";
|
|
182
|
+
if (weights && searchableFields.length > 0) {
|
|
183
|
+
const weightValues = ["0", "0"];
|
|
184
|
+
for (const field of searchableFields) weightValues.push(String(weights[field] ?? 1));
|
|
185
|
+
bm25Args = weightValues.join(", ");
|
|
186
|
+
}
|
|
187
|
+
const bm25Expr = bm25Args ? `bm25("${ftsTable}", ${bm25Args})` : `bm25("${ftsTable}")`;
|
|
188
|
+
let results;
|
|
189
|
+
try {
|
|
190
|
+
results = await sql`
|
|
191
|
+
SELECT
|
|
192
|
+
c.id,
|
|
193
|
+
c.slug,
|
|
194
|
+
c.locale,
|
|
195
|
+
${titleExpr} as title,
|
|
196
|
+
snippet("${sql.raw(ftsTable)}", 2, '<mark>', '</mark>', '...', 32) as snippet,
|
|
197
|
+
${sql.raw(bm25Expr)} as score
|
|
198
|
+
FROM "${sql.raw(ftsTable)}" f
|
|
199
|
+
JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
|
|
200
|
+
WHERE "${sql.raw(ftsTable)}" MATCH ${matchQuery}
|
|
201
|
+
AND c.status = ${status}
|
|
202
|
+
AND c.deleted_at IS NULL
|
|
203
|
+
${locale ? sql`AND c.locale = ${locale}` : sql``}
|
|
204
|
+
ORDER BY score
|
|
205
|
+
LIMIT ${limit}
|
|
206
|
+
`.execute(db);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (isFts5SyntaxError(error)) return [];
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
return results.rows.map((row) => ({
|
|
212
|
+
collection,
|
|
213
|
+
id: row.id,
|
|
214
|
+
slug: row.slug,
|
|
215
|
+
locale: row.locale,
|
|
216
|
+
title: row.title ?? void 0,
|
|
217
|
+
snippet: row.snippet === null ? void 0 : sanitizeSnippet(row.snippet),
|
|
218
|
+
score: Math.abs(row.score)
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
const SNIPPET_AMP_RE = /&/g;
|
|
222
|
+
const SNIPPET_LT_RE = /</g;
|
|
223
|
+
const SNIPPET_GT_RE = />/g;
|
|
224
|
+
const SNIPPET_QUOT_RE = /"/g;
|
|
225
|
+
const SNIPPET_APOS_RE = /'/g;
|
|
226
|
+
/**
|
|
227
|
+
* Make an FTS5 snippet safe to render with `set:html` / `innerHTML`.
|
|
228
|
+
*
|
|
229
|
+
* SQLite's `snippet()` function splices literal `<mark>` and `</mark>`
|
|
230
|
+
* markers around matched terms but does not escape the surrounding
|
|
231
|
+
* source text. Posts that legitimately contain `<`, `>`, `&`, `"` or
|
|
232
|
+
* `'` would render as broken markup, and a `<script>` literal in a
|
|
233
|
+
* title (or any other indexed field) would execute when displayed.
|
|
234
|
+
*
|
|
235
|
+
* The fix: HTML-escape the whole string, which turns the markers into
|
|
236
|
+
* `<mark>` / `</mark>`. Then restore those two patterns to
|
|
237
|
+
* their original tag form. The result is "the indexed text with all
|
|
238
|
+
* HTML metacharacters escaped, plus a small set of literal `<mark>`
|
|
239
|
+
* highlight tags around matched terms" — which matches the API's
|
|
240
|
+
* documented contract.
|
|
241
|
+
*/
|
|
242
|
+
function sanitizeSnippet(snippet) {
|
|
243
|
+
return snippet.replace(SNIPPET_AMP_RE, "&").replace(SNIPPET_LT_RE, "<").replace(SNIPPET_GT_RE, ">").replace(SNIPPET_QUOT_RE, """).replace(SNIPPET_APOS_RE, "'").replaceAll("<mark>", "<mark>").replaceAll("</mark>", "</mark>");
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get search suggestions for autocomplete
|
|
247
|
+
*
|
|
248
|
+
* @param db - Kysely database instance
|
|
249
|
+
* @param query - Partial search query
|
|
250
|
+
* @param options - Suggestion options
|
|
251
|
+
* @returns Array of suggestions
|
|
252
|
+
*/
|
|
253
|
+
async function getSuggestions(db, query, options = {}) {
|
|
254
|
+
const limit = options.limit ?? 5;
|
|
255
|
+
const locale = options.locale ? resolveConfiguredLocale(options.locale) : void 0;
|
|
256
|
+
let collections = options.collections;
|
|
257
|
+
if (!collections || collections.length === 0) collections = await getSearchableCollections(db);
|
|
258
|
+
if (collections.length === 0) return [];
|
|
259
|
+
const suggestions = [];
|
|
260
|
+
const ftsManager = new FTSManager(db);
|
|
261
|
+
const titleColumns = await ftsManager.getCollectionsWithTitleColumn(collections);
|
|
262
|
+
for (const collection of collections) {
|
|
263
|
+
const config = await ftsManager.getSearchConfig(collection);
|
|
264
|
+
if (!config?.enabled) continue;
|
|
265
|
+
let titleExpr;
|
|
266
|
+
if (config.titleField) {
|
|
267
|
+
validateIdentifier(config.titleField, "title field");
|
|
268
|
+
titleExpr = sql`c.${sql.ref(config.titleField)}`;
|
|
269
|
+
} else if (titleColumns.has(collection)) titleExpr = sql`c.title`;
|
|
270
|
+
else continue;
|
|
271
|
+
validateIdentifier(collection, "collection slug");
|
|
272
|
+
const ftsTable = ftsManager.getFtsTableName(collection);
|
|
273
|
+
const contentTable = ftsManager.getContentTableName(collection);
|
|
274
|
+
const prefixQuery = escapeQuery(query);
|
|
275
|
+
if (!prefixQuery) continue;
|
|
276
|
+
let results;
|
|
277
|
+
try {
|
|
278
|
+
results = await sql`
|
|
279
|
+
SELECT
|
|
280
|
+
c.id,
|
|
281
|
+
c.slug,
|
|
282
|
+
${titleExpr} AS title
|
|
283
|
+
FROM "${sql.raw(ftsTable)}" f
|
|
284
|
+
JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
|
|
285
|
+
WHERE "${sql.raw(ftsTable)}" MATCH ${prefixQuery}
|
|
286
|
+
AND c.status = 'published'
|
|
287
|
+
AND c.deleted_at IS NULL
|
|
288
|
+
AND ${titleExpr} IS NOT NULL
|
|
289
|
+
${locale ? sql`AND c.locale = ${locale}` : sql``}
|
|
290
|
+
ORDER BY bm25("${sql.raw(ftsTable)}")
|
|
291
|
+
LIMIT ${limit}
|
|
292
|
+
`.execute(db);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if (isFts5SyntaxError(error)) continue;
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
for (const row of results.rows) suggestions.push({
|
|
298
|
+
collection,
|
|
299
|
+
id: row.id,
|
|
300
|
+
slug: row.slug,
|
|
301
|
+
title: row.title
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return suggestions.slice(0, limit);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get search statistics for all collections
|
|
308
|
+
*/
|
|
309
|
+
async function getSearchStats(db) {
|
|
310
|
+
const ftsManager = new FTSManager(db);
|
|
311
|
+
const collections = await getSearchableCollections(db);
|
|
312
|
+
const stats = { collections: {} };
|
|
313
|
+
for (const collection of collections) {
|
|
314
|
+
const collectionStats = await ftsManager.getIndexStats(collection);
|
|
315
|
+
if (collectionStats) stats.collections[collection] = collectionStats;
|
|
316
|
+
}
|
|
317
|
+
return stats;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get list of collections with search enabled
|
|
321
|
+
*/
|
|
322
|
+
async function getSearchableCollections(db) {
|
|
323
|
+
return (await db.selectFrom("_emdash_collections").select(["slug", "search_config"]).execute()).filter((r) => {
|
|
324
|
+
if (!r.search_config) return false;
|
|
325
|
+
try {
|
|
326
|
+
return JSON.parse(r.search_config).enabled === true;
|
|
327
|
+
} catch {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
}).map((r) => r.slug);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Escape a query string for FTS5
|
|
334
|
+
*
|
|
335
|
+
* Handles special characters and prevents injection.
|
|
336
|
+
*/
|
|
337
|
+
function escapeQuery(query, allowOperators = true) {
|
|
338
|
+
if (!query || typeof query !== "string") return "";
|
|
339
|
+
query = query.trim();
|
|
340
|
+
if (query.length === 0) return "";
|
|
341
|
+
if (query.startsWith("\"") && query.endsWith("\"") && query.length >= 2) return `"${query.slice(1, -1).replace(DOUBLE_QUOTE_PATTERN, "\"\"")}"`;
|
|
342
|
+
const escaped = query.replace(DOUBLE_QUOTE_PATTERN, "\"\"");
|
|
343
|
+
if (allowOperators && FTS_OPERATORS_PATTERN.test(query)) return escaped;
|
|
344
|
+
const terms = escaped.split(WHITESPACE_SPLIT_PATTERN).filter((t) => t.length > 0);
|
|
345
|
+
if (terms.length === 0) return "";
|
|
346
|
+
return terms.map((t) => `"${t}"*`).join(" ");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/search/text-extraction.ts
|
|
351
|
+
/**
|
|
352
|
+
* Text Extraction
|
|
353
|
+
*
|
|
354
|
+
* Extracts plain text from Portable Text blocks for FTS indexing.
|
|
355
|
+
* Uses @portabletext/toolkit as base with extensions for custom block types.
|
|
356
|
+
*/
|
|
357
|
+
/**
|
|
358
|
+
* Validate that a value looks like a Portable Text block array.
|
|
359
|
+
* Each element must have at least a `_type` string property.
|
|
360
|
+
*/
|
|
361
|
+
function isPortableTextArray(value) {
|
|
362
|
+
return value.every((item) => typeof item === "object" && item !== null && "_type" in item && typeof item._type === "string");
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Extract additional text from custom block types that toPlainText doesn't handle
|
|
366
|
+
*/
|
|
367
|
+
function extractCustomBlockText(block) {
|
|
368
|
+
if (block._type === "code" && "code" in block && typeof block.code === "string") return block.code;
|
|
369
|
+
if (block._type === "image") {
|
|
370
|
+
const parts = [];
|
|
371
|
+
if ("alt" in block && typeof block.alt === "string" && block.alt) parts.push(block.alt);
|
|
372
|
+
if ("caption" in block && typeof block.caption === "string" && block.caption) parts.push(block.caption);
|
|
373
|
+
return parts.join(" ");
|
|
374
|
+
}
|
|
375
|
+
return "";
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Extract plain text from Portable Text blocks
|
|
379
|
+
*
|
|
380
|
+
* Uses @portabletext/toolkit's toPlainText for standard blocks,
|
|
381
|
+
* plus extracts text from custom block types (code, images with alt/caption).
|
|
382
|
+
*
|
|
383
|
+
* @param blocks - Array of Portable Text blocks (or a JSON string)
|
|
384
|
+
* @returns Plain text content
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* const text = extractPlainText([
|
|
389
|
+
* {
|
|
390
|
+
* _type: "block",
|
|
391
|
+
* _key: "abc",
|
|
392
|
+
* children: [{ _type: "span", _key: "s1", text: "Hello World" }]
|
|
393
|
+
* }
|
|
394
|
+
* ]);
|
|
395
|
+
* // Returns: "Hello World"
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
function extractPlainText(blocks) {
|
|
399
|
+
if (!blocks) return "";
|
|
400
|
+
let parsedBlocks;
|
|
401
|
+
if (typeof blocks === "string") try {
|
|
402
|
+
parsedBlocks = JSON.parse(blocks);
|
|
403
|
+
} catch {
|
|
404
|
+
return blocks;
|
|
405
|
+
}
|
|
406
|
+
else parsedBlocks = blocks;
|
|
407
|
+
if (!Array.isArray(parsedBlocks)) return "";
|
|
408
|
+
return [toPlainText(parsedBlocks.map((b) => {
|
|
409
|
+
const obj = { _type: b._type };
|
|
410
|
+
for (const [key, val] of Object.entries(b)) obj[key] = val;
|
|
411
|
+
return obj;
|
|
412
|
+
})), ...parsedBlocks.map(extractCustomBlockText).filter((text) => text.length > 0)].filter((t) => t.length > 0).join("\n");
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Extract searchable text from a content entry
|
|
416
|
+
*
|
|
417
|
+
* Extracts text from specified fields, handling both plain text and Portable Text.
|
|
418
|
+
*
|
|
419
|
+
* @param entry - Content entry data
|
|
420
|
+
* @param fields - Field names to extract text from
|
|
421
|
+
* @returns Object mapping field names to extracted text
|
|
422
|
+
*/
|
|
423
|
+
function extractSearchableFields(entry, fields) {
|
|
424
|
+
const result = {};
|
|
425
|
+
for (const field of fields) {
|
|
426
|
+
const value = entry[field];
|
|
427
|
+
if (value === null || value === void 0) {
|
|
428
|
+
result[field] = "";
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (typeof value === "string") if (value.startsWith("[")) result[field] = extractPlainText(value);
|
|
432
|
+
else result[field] = value;
|
|
433
|
+
else if (Array.isArray(value)) if (isPortableTextArray(value)) result[field] = extractPlainText(value);
|
|
434
|
+
else result[field] = JSON.stringify(value);
|
|
435
|
+
else if (typeof value === "object") result[field] = JSON.stringify(value);
|
|
436
|
+
else if (typeof value === "number" || typeof value === "boolean") result[field] = `${value}`;
|
|
437
|
+
else result[field] = "";
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/search/index.ts
|
|
444
|
+
var search_exports = /* @__PURE__ */ __exportAll({ searchWithDb: () => searchWithDb });
|
|
445
|
+
|
|
446
|
+
//#endregion
|
|
447
|
+
export { getSuggestions as a, searchWithDb as c, getSearchStats as i, extractPlainText as n, search as o, extractSearchableFields as r, searchCollection as s, search_exports as t };
|
|
448
|
+
//# sourceMappingURL=search-YJKPIEV6.mjs.map
|