emdash 0.33.0 → 0.34.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/{adapters-BMyNSSZi.d.mts → adapters-34EN2eXO.d.mts} +26 -2
- package/dist/adapters-34EN2eXO.d.mts.map +1 -0
- package/dist/{allowed-origins-CG1pACtS.mjs → allowed-origins-DW7sYyqg.mjs} +2 -2
- package/dist/{allowed-origins-CG1pACtS.mjs.map → allowed-origins-DW7sYyqg.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +22 -21
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +6 -5
- package/dist/{api-D2hunekQ.mjs → api-DdAsirBe.mjs} +98 -407
- package/dist/api-DdAsirBe.mjs.map +1 -0
- package/dist/{api-tokens-CSND0i1z.mjs → api-tokens-CFXu8F_2.mjs} +2 -2
- package/dist/{api-tokens-CSND0i1z.mjs.map → api-tokens-CFXu8F_2.mjs.map} +1 -1
- package/dist/{apply-kwNEJW2l.mjs → apply-D5zfeD09.mjs} +131 -107
- package/dist/apply-D5zfeD09.mjs.map +1 -0
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +93 -35
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +8 -8
- package/dist/astro/middleware/media-usage-write-fence.d.mts +7 -0
- package/dist/astro/middleware/media-usage-write-fence.d.mts.map +1 -0
- package/dist/astro/middleware/media-usage-write-fence.mjs +35 -0
- package/dist/astro/middleware/media-usage-write-fence.mjs.map +1 -0
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +10 -7
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +12 -11
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +1677 -156
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +9 -8
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +9 -8
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +12 -11
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +12 -11
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +12 -11
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/index.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +14 -13
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -11
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/index.mjs +12 -11
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +36 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.d.mts +8 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +36 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +15 -14
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/media-usage/work/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +37 -0
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/work/retry.d.mts +8 -0
- package/dist/astro/routes/api/admin/media-usage/work/retry.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +37 -0
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -0
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +51 -43
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +51 -43
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +50 -42
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +50 -42
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +50 -42
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +50 -42
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +51 -43
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +51 -43
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +47 -42
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +47 -42
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +47 -42
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +9 -8
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
- package/dist/astro/routes/api/admin/users/index.mjs +9 -8
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/complete.mjs +13 -12
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/index.mjs +10 -9
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/register-options.mjs +12 -11
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/logout.mjs +4 -4
- package/dist/astro/routes/api/auth/magic-link/send.mjs +12 -11
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
- package/dist/astro/routes/api/auth/me.mjs +10 -9
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +9 -8
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/options.mjs +14 -13
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +12 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +13 -12
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/verify.mjs +13 -12
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/complete.mjs +13 -12
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/request.mjs +12 -11
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +15 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +14 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +18 -17
- 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 +18 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +44 -31
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
- package/dist/astro/routes/api/dashboard.mjs +10 -8
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +4 -4
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +18 -16
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +15 -15
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +14 -12
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +13 -12
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +14 -14
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +18 -16
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +28 -27
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +5 -5
- package/dist/astro/routes/api/mcp.d.mts.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +174 -72
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +13 -11
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +17 -16
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +16 -15
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
- package/dist/astro/routes/api/media/providers/index.mjs +4 -4
- package/dist/astro/routes/api/media/upload-url.mjs +11 -10
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +18 -15
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +11 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs +11 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +11 -11
- package/dist/astro/routes/api/menus/_name_/translations.mjs +11 -11
- package/dist/astro/routes/api/menus/_name_.mjs +11 -11
- package/dist/astro/routes/api/menus/index.mjs +11 -11
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
- package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
- package/dist/astro/routes/api/oauth/register.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
- package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
- package/dist/astro/routes/api/oauth/token.mjs +7 -7
- package/dist/astro/routes/api/openapi.json.mjs +152 -6
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +8 -7
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +13 -12
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +13 -12
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/index.mjs +18 -17
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +13 -12
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +18 -17
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +47 -42
- 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 +47 -42
- 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 +47 -42
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +47 -42
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +47 -42
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +47 -42
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +10 -9
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +47 -42
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +47 -42
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +13 -13
- package/dist/astro/routes/api/search/index.mjs +12 -12
- package/dist/astro/routes/api/search/rebuild.mjs +13 -13
- package/dist/astro/routes/api/search/stats.mjs +8 -8
- package/dist/astro/routes/api/search/suggest.mjs +12 -12
- package/dist/astro/routes/api/sections/_slug_.mjs +12 -11
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +12 -11
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +6 -6
- 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 +5 -5
- package/dist/astro/routes/api/settings.mjs +14 -13
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +14 -13
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin.mjs +13 -12
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +30 -28
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
- package/dist/astro/routes/api/setup/index.mjs +32 -30
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +5 -5
- package/dist/astro/routes/api/snapshot.mjs +8 -8
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +18 -16
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.d.mts +8 -0
- package/dist/astro/routes/api/taxonomies/_name_/translations.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +46 -0
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_.d.mts +19 -0
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_.mjs +88 -0
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/index.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +6 -6
- package/dist/astro/routes/api/typegen.mjs +6 -6
- 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 +10 -9
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +12 -11
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +12 -11
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -6
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +12 -11
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +4 -4
- package/dist/astro/routes/robots.txt.mjs +7 -6
- package/dist/astro/routes/robots.txt.mjs.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +10 -10
- package/dist/astro/routes/sitemap.xml.mjs +8 -7
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +35 -17
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-qRhWQnel.mjs → authorize-1iFJzPaZ.mjs} +2 -2
- package/dist/{authorize-qRhWQnel.mjs.map → authorize-1iFJzPaZ.mjs.map} +1 -1
- package/dist/{backup-CtA6LDNw.mjs → backup-LHjIAVNP.mjs} +4 -4
- package/dist/{backup-CtA6LDNw.mjs.map → backup-LHjIAVNP.mjs.map} +1 -1
- package/dist/{base64-B-PsqheR.mjs → base64-CvLhUKQv.mjs} +1 -1
- package/dist/{base64-B-PsqheR.mjs.map → base64-CvLhUKQv.mjs.map} +1 -1
- package/dist/bundle-CBEXrBnb.mjs +663 -0
- package/dist/bundle-CBEXrBnb.mjs.map +1 -0
- package/dist/{byline-fields-CNc0Yq5i.mjs → byline-fields-C5S8wygO.mjs} +2 -2
- package/dist/{byline-fields-CNc0Yq5i.mjs.map → byline-fields-C5S8wygO.mjs.map} +1 -1
- package/dist/{byline-Cp6csL84.mjs → byline-pEcoDps8.mjs} +5 -5
- package/dist/{byline-Cp6csL84.mjs.map → byline-pEcoDps8.mjs.map} +1 -1
- package/dist/{byline-registry-ZkPKqEwC.mjs → byline-registry-DDun8sxh.mjs} +2 -2
- package/dist/{byline-registry-ZkPKqEwC.mjs.map → byline-registry-DDun8sxh.mjs.map} +1 -1
- package/dist/{bylines-CEj5CdT4.mjs → bylines-BWemdX2k.mjs} +7 -7
- package/dist/{bylines-CEj5CdT4.mjs.map → bylines-BWemdX2k.mjs.map} +1 -1
- package/dist/{bylines-cf-C9lmF.mjs → bylines-DJfSfXCL.mjs} +5 -5
- package/dist/{bylines-cf-C9lmF.mjs.map → bylines-DJfSfXCL.mjs.map} +1 -1
- package/dist/{cache-C9FptTFR.mjs → cache-CBJaDy_E.mjs} +3 -3
- package/dist/{cache-C9FptTFR.mjs.map → cache-CBJaDy_E.mjs.map} +1 -1
- package/dist/{challenge-store-D9VNKELo.mjs → challenge-store-CZyFVaad.mjs} +1 -1
- package/dist/{challenge-store-D9VNKELo.mjs.map → challenge-store-CZyFVaad.mjs.map} +1 -1
- package/dist/{chunks-DbYzib_k.mjs → chunks-DfPax1I0.mjs} +2 -2
- package/dist/{chunks-DbYzib_k.mjs.map → chunks-DfPax1I0.mjs.map} +1 -1
- package/dist/cli/index.mjs +176 -698
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +74 -4
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +25 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/collection-deletion-C8BugSGz.mjs +779 -0
- package/dist/collection-deletion-C8BugSGz.mjs.map +1 -0
- package/dist/{comment-BIkJ6Fil.mjs → comment-Dxlep6cE.mjs} +2 -2
- package/dist/{comment-BIkJ6Fil.mjs.map → comment-Dxlep6cE.mjs.map} +1 -1
- package/dist/{comment-reaction-D-laEceb.mjs → comment-reaction-D6qfHKBc.mjs} +2 -2
- package/dist/{comment-reaction-D-laEceb.mjs.map → comment-reaction-D6qfHKBc.mjs.map} +1 -1
- package/dist/{comments-0_w6KChA.mjs → comments-CTOuhTSX.mjs} +3 -3
- package/dist/{comments-0_w6KChA.mjs.map → comments-CTOuhTSX.mjs.map} +1 -1
- package/dist/{components-BPxrRjpE.mjs → components-CQy3lh9x.mjs} +1 -1
- package/dist/{components-BPxrRjpE.mjs.map → components-CQy3lh9x.mjs.map} +1 -1
- package/dist/{config-DyF3OKg_.mjs → config-C3EBstHi.mjs} +18 -2
- package/dist/config-C3EBstHi.mjs.map +1 -0
- package/dist/{content-CJ94NEx5.mjs → content-BNfwh7xX.mjs} +509 -78
- package/dist/content-BNfwh7xX.mjs.map +1 -0
- package/dist/content-list-query-DhQ84eVV.d.mts +26 -0
- package/dist/content-list-query-DhQ84eVV.d.mts.map +1 -0
- package/dist/content-refresh-DNERP4-f.mjs +2560 -0
- package/dist/content-refresh-DNERP4-f.mjs.map +1 -0
- package/dist/{context-C_1nrqnW.mjs → context-DRgOvSnW.mjs} +25 -17
- package/dist/context-DRgOvSnW.mjs.map +1 -0
- package/dist/{cron-DRV-UC4K.mjs → cron-Y9aLtgrA.mjs} +1 -1
- package/dist/{cron-DRV-UC4K.mjs.map → cron-Y9aLtgrA.mjs.map} +1 -1
- package/dist/{dashboard-DINnNVVU.mjs → dashboard-CB8J89rJ.mjs} +44 -10
- package/dist/dashboard-CB8J89rJ.mjs.map +1 -0
- package/dist/db/index.d.mts +4 -4
- package/dist/db/index.mjs +2 -2
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-CcWLaRiR.mjs → db-errors-Cl-sKYTm.mjs} +1 -1
- package/dist/{db-errors-CcWLaRiR.mjs.map → db-errors-Cl-sKYTm.mjs.map} +1 -1
- package/dist/{default-BD2FG0xV.mjs → default-DdDl3fxv.mjs} +1 -1
- package/dist/{default-BD2FG0xV.mjs.map → default-DdDl3fxv.mjs.map} +1 -1
- package/dist/{deferred-tasks-C-WRCcKo.d.mts → deferred-tasks-BMsa9F64.d.mts} +1 -1
- package/dist/{deferred-tasks-C-WRCcKo.d.mts.map → deferred-tasks-BMsa9F64.d.mts.map} +1 -1
- package/dist/{device-flow-CTqd8mud.mjs → device-flow-CaioYGK3.mjs} +4 -4
- package/dist/{device-flow-CTqd8mud.mjs.map → device-flow-CaioYGK3.mjs.map} +1 -1
- package/dist/dist-D_6CKR8z.mjs +810 -0
- package/dist/dist-D_6CKR8z.mjs.map +1 -0
- package/dist/{email-console-C6WdcWbL.mjs → email-console-BHNjIwiB.mjs} +1 -1
- package/dist/{email-console-C6WdcWbL.mjs.map → email-console-BHNjIwiB.mjs.map} +1 -1
- package/dist/{enrich-CFJJgxs_.mjs → enrich-_ySMEvEE.mjs} +2 -2
- package/dist/{enrich-CFJJgxs_.mjs.map → enrich-_ySMEvEE.mjs.map} +1 -1
- package/dist/{error-oh_9i6bR.mjs → error-DupyJZE2.mjs} +3 -3
- package/dist/{error-oh_9i6bR.mjs.map → error-DupyJZE2.mjs.map} +1 -1
- package/dist/{errors-BucQ8VYz.mjs → errors-CLUPm7aD.mjs} +14 -2
- package/dist/errors-CLUPm7aD.mjs.map +1 -0
- package/dist/{escape-CXps5F_v.mjs → escape-C_aLKP3H.mjs} +1 -1
- package/dist/{escape-CXps5F_v.mjs.map → escape-C_aLKP3H.mjs.map} +1 -1
- package/dist/{field-defs-cache-WD82dMQq.mjs → field-defs-cache-hg6QkjV9.mjs} +4 -4
- package/dist/{field-defs-cache-WD82dMQq.mjs.map → field-defs-cache-hg6QkjV9.mjs.map} +1 -1
- package/dist/{fts-manager-BITakW_R.mjs → fts-manager-CZ-5dVwJ.mjs} +76 -50
- package/dist/fts-manager-CZ-5dVwJ.mjs.map +1 -0
- package/dist/{hreflang-BaLCNcDx.d.mts → hreflang-D3Uehfv2.d.mts} +2 -2
- package/dist/{hreflang-BaLCNcDx.d.mts.map → hreflang-D3Uehfv2.d.mts.map} +1 -1
- package/dist/{hreflang-BdZuVBhL.mjs → hreflang-DNswoYsi.mjs} +7 -7
- package/dist/{hreflang-BdZuVBhL.mjs.map → hreflang-DNswoYsi.mjs.map} +1 -1
- package/dist/{import-C-9uqyT3.mjs → import-B41u8Rot.mjs} +5 -5
- package/dist/{import-C-9uqyT3.mjs.map → import-B41u8Rot.mjs.map} +1 -1
- package/dist/{index-M37iz29I.d.mts → index-C3Y-rsyN.d.mts} +226 -73
- package/dist/index-C3Y-rsyN.d.mts.map +1 -0
- package/dist/{index-MGw47uWq.d.mts → index-Cof4-Fab.d.mts} +5 -10
- package/dist/index-Cof4-Fab.d.mts.map +1 -0
- package/dist/index.d.mts +20 -19
- package/dist/index.mjs +73 -67
- package/dist/{init-lock-DJkX6Hto.mjs → init-lock-6b309ZrF.mjs} +1 -1
- package/dist/{init-lock-DJkX6Hto.mjs.map → init-lock-6b309ZrF.mjs.map} +1 -1
- package/dist/{load-DV1DZuUJ.mjs → load-DmvJrtxS.mjs} +2 -2
- package/dist/{load-DV1DZuUJ.mjs.map → load-DmvJrtxS.mjs.map} +1 -1
- package/dist/{loader-CGugY7Zl.mjs → loader-DLBqRiGP.mjs} +95 -53
- package/dist/loader-DLBqRiGP.mjs.map +1 -0
- package/dist/{manifest-schema-Da7kj23y.mjs → manifest-schema-BXbUAHod.mjs} +1 -1
- package/dist/{manifest-schema-Da7kj23y.mjs.map → manifest-schema-BXbUAHod.mjs.map} +1 -1
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +3 -2
- package/dist/media/index.mjs.map +1 -1
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +6 -5
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-OhYL-7Io.mjs → media-BWWWb8kg.mjs} +92 -3
- package/dist/media-BWWWb8kg.mjs.map +1 -0
- package/dist/{media-BP7S-nHT.mjs → media-CzhAn2--.mjs} +2 -2
- package/dist/{media-BP7S-nHT.mjs.map → media-CzhAn2--.mjs.map} +1 -1
- package/dist/{media-allowlist-D-peH1H5.mjs → media-allowlist-BD6HhgXA.mjs} +14 -3
- package/dist/media-allowlist-BD6HhgXA.mjs.map +1 -0
- package/dist/{media-upload-DtrwU2B0.mjs → media-upload-9yas9zGH.mjs} +10 -8
- package/dist/{media-upload-DtrwU2B0.mjs.map → media-upload-9yas9zGH.mjs.map} +1 -1
- package/dist/{media-url-DYs_YLOx.mjs → media-url-BvoX88FA.mjs} +1 -1
- package/dist/{media-url-DYs_YLOx.mjs.map → media-url-BvoX88FA.mjs.map} +1 -1
- package/dist/{media-usage-BlxfTkN0.mjs → media-usage-De3qvwjc.mjs} +137 -60
- package/dist/media-usage-De3qvwjc.mjs.map +1 -0
- package/dist/media-usage-work-B9Bksh_b.mjs +152 -0
- package/dist/media-usage-work-B9Bksh_b.mjs.map +1 -0
- package/dist/media-usage-work-DrCbqBcl.mjs +424 -0
- package/dist/media-usage-work-DrCbqBcl.mjs.map +1 -0
- package/dist/media-usage-write-fence-aHEgN1zB.mjs +42 -0
- package/dist/media-usage-write-fence-aHEgN1zB.mjs.map +1 -0
- package/dist/{menus-Y54RDPIN.mjs → menus-CC-yn1F9.mjs} +351 -95
- package/dist/menus-CC-yn1F9.mjs.map +1 -0
- package/dist/{menus-BcQWxeXu.mjs → menus-fxvEDYE6.mjs} +3 -3
- package/dist/{menus-BcQWxeXu.mjs.map → menus-fxvEDYE6.mjs.map} +1 -1
- package/dist/{mode-BWyTBe3I.mjs → mode-Bpe-tNNy.mjs} +1 -1
- package/dist/{mode-BWyTBe3I.mjs.map → mode-Bpe-tNNy.mjs.map} +1 -1
- package/dist/{normalize-C-SHXmra.mjs → normalize-Bc-s_r-a.mjs} +1 -1
- package/dist/{normalize-C-SHXmra.mjs.map → normalize-Bc-s_r-a.mjs.map} +1 -1
- package/dist/{oauth-authorization-ClvktmrL.mjs → oauth-authorization-BXO1MKej.mjs} +4 -4
- package/dist/{oauth-authorization-ClvktmrL.mjs.map → oauth-authorization-BXO1MKej.mjs.map} +1 -1
- package/dist/{oauth-clients-8ao-U66l.mjs → oauth-clients-C_DNqtRu.mjs} +1 -1
- package/dist/{oauth-clients-8ao-U66l.mjs.map → oauth-clients-C_DNqtRu.mjs.map} +1 -1
- package/dist/{oauth-state-store-B1ofdTiQ.mjs → oauth-state-store-DwAxMtk4.mjs} +1 -1
- package/dist/{oauth-state-store-B1ofdTiQ.mjs.map → oauth-state-store-DwAxMtk4.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-CscEuIiR.mjs → oauth-user-lookup-BxfZizdk.mjs} +1 -1
- package/dist/{oauth-user-lookup-CscEuIiR.mjs.map → oauth-user-lookup-BxfZizdk.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-CA4eVX6P.d.mts → options-DRe1pIBL.d.mts} +4 -3
- package/dist/options-DRe1pIBL.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-CJKNuewM.mjs → parse-DFbuc-Fh.mjs} +2 -2
- package/dist/{parse-CJKNuewM.mjs.map → parse-DFbuc-Fh.mjs.map} +1 -1
- package/dist/{passkey-config-D-zrzMJI.mjs → passkey-config-_2GOwwK8.mjs} +1 -1
- package/dist/{passkey-config-D-zrzMJI.mjs.map → passkey-config-_2GOwwK8.mjs.map} +1 -1
- package/dist/{placeholder-DaeNS-VG.d.mts → placeholder-CzW7Lshs.d.mts} +1 -1
- package/dist/{placeholder-DaeNS-VG.d.mts.map → placeholder-CzW7Lshs.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +8 -1
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +7 -4
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/{portable-text-B_kqBmXB.mjs → portable-text-DhKbDAGr.mjs} +1 -1
- package/dist/{portable-text-B_kqBmXB.mjs.map → portable-text-DhKbDAGr.mjs.map} +1 -1
- package/dist/{preview-BU6PaLpM.mjs → preview-PW-nOnq4.mjs} +2 -2
- package/dist/{preview-BU6PaLpM.mjs.map → preview-PW-nOnq4.mjs.map} +1 -1
- package/dist/{public-url-Ox9oOlgp.mjs → public-url-CWoFhQT8.mjs} +1 -1
- package/dist/{public-url-Ox9oOlgp.mjs.map → public-url-CWoFhQT8.mjs.map} +1 -1
- package/dist/{query-C5w7PsRQ.mjs → query-BgjfiLUQ.mjs} +31 -49
- package/dist/query-BgjfiLUQ.mjs.map +1 -0
- package/dist/{query-rC9HKv1N.mjs → query-vgZNwIhh.mjs} +3 -3
- package/dist/{query-rC9HKv1N.mjs.map → query-vgZNwIhh.mjs.map} +1 -1
- package/dist/{rate-limit-kug6q99V.mjs → rate-limit-L5anykgo.mjs} +2 -2
- package/dist/{rate-limit-kug6q99V.mjs.map → rate-limit-L5anykgo.mjs.map} +1 -1
- package/dist/{redirect-DIJxXKOG.mjs → redirect-COsS6SWJ.mjs} +2 -2
- package/dist/{redirect-DIJxXKOG.mjs.map → redirect-COsS6SWJ.mjs.map} +1 -1
- package/dist/{redirect-Egf2R9yP.mjs → redirect-KBNE3UEs.mjs} +1 -1
- package/dist/{redirect-Egf2R9yP.mjs.map → redirect-KBNE3UEs.mjs.map} +1 -1
- package/dist/{redirects-Bzm812bY.mjs → redirects-CufRQt0Q.mjs} +4 -4
- package/dist/{redirects-Bzm812bY.mjs.map → redirects-CufRQt0Q.mjs.map} +1 -1
- package/dist/{redirects-G8wAhWAf.mjs → redirects-cV9g7V-0.mjs} +133 -14
- package/dist/redirects-cV9g7V-0.mjs.map +1 -0
- package/dist/registry-C581V4TP.mjs +1275 -0
- package/dist/registry-C581V4TP.mjs.map +1 -0
- package/dist/{relation-Cbe3Sd3m.mjs → relation-DtmAQH7s.mjs} +3 -3
- package/dist/{relation-Cbe3Sd3m.mjs.map → relation-DtmAQH7s.mjs.map} +1 -1
- package/dist/{relations-Bw_E1TXo.mjs → relations-BBApI4e2.mjs} +3 -3
- package/dist/{relations-Bw_E1TXo.mjs.map → relations-BBApI4e2.mjs.map} +1 -1
- package/dist/{relations-qHwpUe66.mjs → relations-DICSyfsh.mjs} +6 -6
- package/dist/{relations-qHwpUe66.mjs.map → relations-DICSyfsh.mjs.map} +1 -1
- package/dist/{relations-G2ta7GIl.d.mts → relations-DItI3MN9.d.mts} +369 -35
- package/dist/relations-DItI3MN9.d.mts.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-Df-jFbAd.mjs → request-meta-DgZJh3zG.mjs} +2 -2
- package/dist/{request-meta-Df-jFbAd.mjs.map → request-meta-DgZJh3zG.mjs.map} +1 -1
- package/dist/{resolve-DZzG4HqM.mjs → resolve-DOhVEvty.mjs} +2 -2
- package/dist/{resolve-DZzG4HqM.mjs.map → resolve-DOhVEvty.mjs.map} +1 -1
- package/dist/{runner-BFTrkYhu.mjs → runner-BiDvq5dv.mjs} +1157 -254
- package/dist/runner-BiDvq5dv.mjs.map +1 -0
- package/dist/{runner-BaADli8l.d.mts → runner-CgQbELYC.d.mts} +2 -2
- package/dist/{runner-BaADli8l.d.mts.map → runner-CgQbELYC.d.mts.map} +1 -1
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +4 -3
- package/dist/runtime.mjs.map +1 -1
- package/dist/{schema-CiQXr6_F.mjs → schema-BFyTg38T.mjs} +3 -3
- package/dist/{schema-CiQXr6_F.mjs.map → schema-BFyTg38T.mjs.map} +1 -1
- package/dist/schema-CeQSNwB3.mjs +390 -0
- package/dist/schema-CeQSNwB3.mjs.map +1 -0
- package/dist/{scopes-CNJVT5i5.mjs → scopes-BVeuhGBE.mjs} +3 -3
- package/dist/{scopes-CNJVT5i5.mjs.map → scopes-BVeuhGBE.mjs.map} +1 -1
- package/dist/{search-FZhx5dDU.mjs → search-BpuPKZb0.mjs} +25 -15
- package/dist/search-BpuPKZb0.mjs.map +1 -0
- package/dist/{secrets-DLd8RXee.mjs → secrets-dtYs2hDo.mjs} +3 -3
- package/dist/{secrets-DLd8RXee.mjs.map → secrets-dtYs2hDo.mjs.map} +1 -1
- package/dist/{sections-BrIrMUCn.mjs → sections-COctk6hf.mjs} +3 -3
- package/dist/{sections-BrIrMUCn.mjs.map → sections-COctk6hf.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +24 -22
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +16 -15
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-CobNfOvb.mjs → seo-AFpVvTqr.mjs} +5 -3
- package/dist/seo-AFpVvTqr.mjs.map +1 -0
- package/dist/{seo-DTHRntNC.mjs → seo-CvDxfvFb.mjs} +2 -2
- package/dist/{seo-DTHRntNC.mjs.map → seo-CvDxfvFb.mjs.map} +1 -1
- package/dist/{service-B-pYGPgR.mjs → service-xMiMSTsR.mjs} +3 -3
- package/dist/{service-B-pYGPgR.mjs.map → service-xMiMSTsR.mjs.map} +1 -1
- package/dist/{session-user-BvM9-zNl.mjs → session-user-BzVemLkw.mjs} +1 -1
- package/dist/{session-user-BvM9-zNl.mjs.map → session-user-BzVemLkw.mjs.map} +1 -1
- package/dist/{settings-kJhGiQ4z.mjs → settings-B372MV0p.mjs} +4 -4
- package/dist/{settings-kJhGiQ4z.mjs.map → settings-B372MV0p.mjs.map} +1 -1
- package/dist/{settings-DPHau-WH.mjs → settings-BE9aqn_9.mjs} +3 -3
- package/dist/{settings-DPHau-WH.mjs.map → settings-BE9aqn_9.mjs.map} +1 -1
- package/dist/{setup-complete-u50Qm8rY.mjs → setup-complete-DF7TAfD5.mjs} +1 -1
- package/dist/{setup-complete-u50Qm8rY.mjs.map → setup-complete-DF7TAfD5.mjs.map} +1 -1
- package/dist/{setup-nonce-DCjiiOD2.mjs → setup-nonce-Do-U_cg9.mjs} +1 -1
- package/dist/{setup-nonce-DCjiiOD2.mjs.map → setup-nonce-Do-U_cg9.mjs.map} +1 -1
- package/dist/{single-flight-cache-DW3w11Pu.mjs → single-flight-cache-B0eLKS6K.mjs} +2 -2
- package/dist/{single-flight-cache-DW3w11Pu.mjs.map → single-flight-cache-B0eLKS6K.mjs.map} +1 -1
- package/dist/{site-url-I-lJ5kma.mjs → site-url-Bowsi9T-.mjs} +2 -2
- package/dist/{site-url-I-lJ5kma.mjs.map → site-url-Bowsi9T-.mjs.map} +1 -1
- package/dist/slugify-B994zkXC.mjs +17 -0
- package/dist/slugify-B994zkXC.mjs.map +1 -0
- package/dist/{snapshot-I_fjLDaD.mjs → snapshot-B5h6aPMh.mjs} +1 -1
- package/dist/{snapshot-I_fjLDaD.mjs.map → snapshot-B5h6aPMh.mjs.map} +1 -1
- package/dist/{ssrf-CTa6v21i.mjs → ssrf-Cpvg_n3A.mjs} +1 -1
- package/dist/{ssrf-CTa6v21i.mjs.map → ssrf-Cpvg_n3A.mjs.map} +1 -1
- package/dist/{state-CQvoefYP.mjs → state-DYwPue40.mjs} +1 -1
- package/dist/{state-CQvoefYP.mjs.map → state-DYwPue40.mjs.map} +1 -1
- package/dist/{status-CIsmlC1E.mjs → status-CWVYpbD8.mjs} +1 -1
- package/dist/{status-CIsmlC1E.mjs.map → status-CWVYpbD8.mjs.map} +1 -1
- 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/{taxonomies-CLN1N92E.mjs → taxonomies-B0o9ExNV.mjs} +75 -64
- package/dist/taxonomies-B0o9ExNV.mjs.map +1 -0
- package/dist/{taxonomies-CKuaZER5.mjs → taxonomies-Dk3MAklL.mjs} +280 -56
- package/dist/taxonomies-Dk3MAklL.mjs.map +1 -0
- package/dist/{taxonomy-pOrB2kZe.mjs → taxonomy-CPeM8d2o.mjs} +131 -78
- package/dist/taxonomy-CPeM8d2o.mjs.map +1 -0
- package/dist/{tokens-DagaJGK8.mjs → tokens-C39klX8R.mjs} +2 -2
- package/dist/{tokens-DagaJGK8.mjs.map → tokens-C39klX8R.mjs.map} +1 -1
- package/dist/{transport-DVsa5YYo.mjs → transport--CfOflrp.mjs} +1 -1
- package/dist/{transport-DVsa5YYo.mjs.map → transport--CfOflrp.mjs.map} +1 -1
- package/dist/{transport-CAwTaTp_.d.mts → transport-B_rfeU-a.d.mts} +1 -1
- package/dist/{transport-CAwTaTp_.d.mts.map → transport-B_rfeU-a.d.mts.map} +1 -1
- package/dist/{trusted-proxy-D20_7fyX.mjs → trusted-proxy-CEVekpby.mjs} +1 -1
- package/dist/{trusted-proxy-D20_7fyX.mjs.map → trusted-proxy-CEVekpby.mjs.map} +1 -1
- package/dist/{types-NBI3rF-_.mjs → types-75KIqzL9.mjs} +18 -2
- package/dist/types-75KIqzL9.mjs.map +1 -0
- package/dist/{types-CbUcuxxc.d.mts → types-BPuloofb.d.mts} +1 -1
- package/dist/{types-CbUcuxxc.d.mts.map → types-BPuloofb.d.mts.map} +1 -1
- package/dist/{types-BjxTKxrZ.mjs → types-BW1syrlw.mjs} +1 -1
- package/dist/{types-BjxTKxrZ.mjs.map → types-BW1syrlw.mjs.map} +1 -1
- package/dist/{types-BnFP1M3J.d.mts → types-C3_AbkDP.d.mts} +32 -10
- package/dist/types-C3_AbkDP.d.mts.map +1 -0
- package/dist/{types-Dc4ntQjQ.d.mts → types-CAGdePf3.d.mts} +124 -1
- package/dist/types-CAGdePf3.d.mts.map +1 -0
- package/dist/{types-DLG4IFEQ.d.mts → types-CFUfyt1s.d.mts} +1 -1
- package/dist/{types-DLG4IFEQ.d.mts.map → types-CFUfyt1s.d.mts.map} +1 -1
- package/dist/{types-LoagAGzH.d.mts → types-CPx2lIGo.d.mts} +1 -1
- package/dist/{types-LoagAGzH.d.mts.map → types-CPx2lIGo.d.mts.map} +1 -1
- package/dist/{types-Cd8iuS1J.mjs → types-CQPWhPxE.mjs} +9 -12
- package/dist/types-CQPWhPxE.mjs.map +1 -0
- package/dist/{types-Cz8hNch2.d.mts → types-Cs-TFLNf.d.mts} +25 -5
- package/dist/types-Cs-TFLNf.d.mts.map +1 -0
- package/dist/types-CtzytVXn.mjs.map +1 -1
- package/dist/{types-BGWPMiBO.d.mts → types-D4_1Ga4L.d.mts} +44 -5
- package/dist/types-D4_1Ga4L.d.mts.map +1 -0
- package/dist/{types-C8oz_ayJ.d.mts → types-DefV3OiO.d.mts} +1 -1
- package/dist/{types-C8oz_ayJ.d.mts.map → types-DefV3OiO.d.mts.map} +1 -1
- package/dist/{types-BK6U01Ro.d.mts → types-X0MThr7x.d.mts} +1 -1
- package/dist/{types-BK6U01Ro.d.mts.map → types-X0MThr7x.d.mts.map} +1 -1
- package/dist/{upload-attempts-D8QAFLUJ.mjs → upload-attempts-hlne3iA1.mjs} +1 -1
- package/dist/{upload-attempts-D8QAFLUJ.mjs.map → upload-attempts-hlne3iA1.mjs.map} +1 -1
- package/dist/url-pattern-BHS0V5Ng.mjs +33 -0
- package/dist/url-pattern-BHS0V5Ng.mjs.map +1 -0
- package/dist/{user-DBrq4UVq.mjs → user-sHgJ62SP.mjs} +3 -3
- package/dist/{user-DBrq4UVq.mjs.map → user-sHgJ62SP.mjs.map} +1 -1
- package/dist/{utils-hLzi_2Fn.mjs → utils-D4vD_Y98.mjs} +3 -3
- package/dist/{utils-hLzi_2Fn.mjs.map → utils-D4vD_Y98.mjs.map} +1 -1
- package/dist/{validate-mKo3RxBM.mjs → validate-BkqIG_Uj.mjs} +24 -5
- package/dist/validate-BkqIG_Uj.mjs.map +1 -0
- package/dist/{validate-C3oSmA7F.d.mts → validate-DeGtBN84.d.mts} +15 -7
- package/dist/validate-DeGtBN84.d.mts.map +1 -0
- package/dist/{validation-BgpucsvF.mjs → validation-CiJb_X5o.mjs} +11 -10
- package/dist/{validation-BgpucsvF.mjs.map → validation-CiJb_X5o.mjs.map} +1 -1
- package/dist/version-x0NjTScG.mjs +7 -0
- package/dist/{version-C4PnpmoV.mjs.map → version-x0NjTScG.mjs.map} +1 -1
- package/dist/{widgets-CJJtkiKh.mjs → widgets-Cwzvww0W.mjs} +3 -3
- package/dist/{widgets-CJJtkiKh.mjs.map → widgets-Cwzvww0W.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-Bkpp_2tK.d.mts → wxr-taxonomies-CmC0ZsDr.d.mts} +1 -1
- package/dist/{wxr-taxonomies-Bkpp_2tK.d.mts.map → wxr-taxonomies-CmC0ZsDr.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-9PPSy8X6.mjs → wxr-taxonomies-QZjWxjyk.mjs} +13 -32
- package/dist/{wxr-taxonomies-9PPSy8X6.mjs.map → wxr-taxonomies-QZjWxjyk.mjs.map} +1 -1
- package/dist/{zod-generator-CG64Hnbh.mjs → zod-generator-D11MhxG4.mjs} +52 -5
- package/dist/zod-generator-D11MhxG4.mjs.map +1 -0
- package/package.json +16 -8
- package/src/api/errors.ts +12 -0
- package/src/api/handlers/content.ts +127 -29
- package/src/api/handlers/dashboard.ts +12 -2
- package/src/api/handlers/index.ts +16 -0
- package/src/api/handlers/manifest.ts +2 -0
- package/src/api/handlers/media-allowlist.ts +13 -2
- package/src/api/handlers/media-usage-work.ts +188 -0
- package/src/api/handlers/media-usage.ts +5 -3
- package/src/api/handlers/schema.ts +9 -3
- package/src/api/handlers/seo.ts +5 -2
- package/src/api/handlers/taxonomies.ts +345 -82
- package/src/api/media-usage-write-fence.ts +64 -0
- package/src/api/openapi/document.ts +199 -0
- package/src/api/schemas/common.ts +3 -1
- package/src/api/schemas/content.ts +122 -1
- package/src/api/schemas/media-usage.ts +133 -0
- package/src/api/schemas/schema.ts +78 -3
- package/src/api/schemas/taxonomies.ts +40 -8
- package/src/api/types.ts +1 -0
- package/src/astro/integration/index.ts +55 -42
- package/src/astro/integration/routes.ts +34 -4
- package/src/astro/integration/runtime.ts +15 -0
- package/src/astro/integration/virtual-modules.ts +25 -1
- package/src/astro/integration/vite-config.ts +16 -1
- package/src/astro/middleware/media-usage-write-fence.ts +30 -0
- package/src/astro/middleware/redirect.ts +12 -2
- package/src/astro/middleware.ts +75 -8
- package/src/astro/routes/api/admin/media-usage/collection-deletions/index.ts +22 -0
- package/src/astro/routes/api/admin/media-usage/collection-deletions/retry.ts +22 -0
- package/src/astro/routes/api/admin/media-usage/work/index.ts +26 -0
- package/src/astro/routes/api/admin/media-usage/work/retry.ts +26 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +4 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +4 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +4 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +67 -31
- package/src/astro/routes/api/import/wordpress/execute.ts +3 -10
- package/src/astro/routes/api/mcp.ts +1 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +7 -1
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +1 -7
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +1 -0
- package/src/astro/routes/api/taxonomies/[name]/translations.ts +48 -0
- package/src/astro/routes/api/taxonomies/[name].ts +102 -0
- package/src/astro/types.ts +25 -4
- package/src/cleanup.ts +6 -12
- package/src/cli/commands/doctor.ts +193 -6
- package/src/cli/commands/export-seed.ts +4 -1
- package/src/client/index.ts +119 -0
- package/src/components/Block.astro +12 -0
- package/src/components/InlinePortableTextEditor.tsx +89 -1
- package/src/content/converters/mark-safety.ts +120 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +25 -16
- package/src/content/converters/prosemirror-to-portable-text.ts +12 -2
- package/src/content-list-query.ts +29 -0
- package/src/database/migrations/060_collection_admin_config.ts +16 -0
- package/src/database/migrations/061_media_usage_cleanup.ts +77 -0
- package/src/database/migrations/062_media_usage_cleanup_fence.ts +295 -0
- package/src/database/migrations/063_media_usage_incremental_work.ts +397 -0
- package/src/database/migrations/064_fts_plain_text.ts +253 -0
- package/src/database/migrations/065_media_usage_collection_deletion.ts +85 -0
- package/src/database/migrations/066_media_usage_reconciliation.ts +115 -0
- package/src/database/migrations/067_indexed_content_fields.ts +39 -0
- package/src/database/migrations/068_content_taxonomy_entry_groups.ts +61 -0
- package/src/database/migrations/069_collection_title_date_fields.ts +45 -0
- package/src/database/migrations/070_collection_routable.ts +18 -0
- package/src/database/migrations/runner.ts +22 -0
- package/src/database/repositories/content.ts +861 -96
- package/src/database/repositories/media-usage-work.ts +848 -0
- package/src/database/repositories/media-usage.ts +1502 -138
- package/src/database/repositories/revision.ts +17 -6
- package/src/database/repositories/taxonomy.ts +234 -103
- package/src/database/repositories/types.ts +51 -2
- package/src/database/types.ts +134 -16
- package/src/db/adapters.ts +28 -0
- package/src/db/index.ts +3 -0
- package/src/emdash-runtime.ts +227 -20
- package/src/fields/file.ts +7 -4
- package/src/fields/image.ts +8 -1
- package/src/fields/types.ts +18 -5
- package/src/i18n/config.ts +32 -0
- package/src/i18n/repair-locale-casing.ts +0 -14
- package/src/i18n/taxonomy-locale-diagnostic.ts +47 -0
- package/src/import/wxr-taxonomies.ts +7 -47
- package/src/index.ts +25 -2
- package/src/loader.ts +119 -65
- package/src/mcp/server.ts +242 -34
- package/src/media/usage/activation.ts +626 -0
- package/src/media/usage/capture-triggers.ts +543 -0
- package/src/media/usage/cleanup.ts +305 -0
- package/src/media/usage/collection-deletion-processor.ts +356 -0
- package/src/media/usage/collection-deletion.ts +836 -0
- package/src/media/usage/content-fields.ts +40 -3
- package/src/media/usage/content-refresh.ts +356 -47
- package/src/media/usage/content-repair.ts +180 -61
- package/src/media/usage/content-snapshots.ts +85 -105
- package/src/media/usage/projection-fingerprint.ts +129 -0
- package/src/media/usage/reconciliation-processor.ts +372 -0
- package/src/media/usage/reconciliation.ts +1117 -0
- package/src/media/usage/source-key.ts +4 -0
- package/src/media/usage/types.ts +2 -0
- package/src/media/usage/work-processor.ts +248 -0
- package/src/menus/index.ts +246 -141
- package/src/plugin-types.ts +8 -0
- package/src/plugins/adapt-sandbox-entry.ts +24 -5
- package/src/plugins/context.ts +24 -7
- package/src/plugins/index.ts +9 -0
- package/src/plugins/routes.ts +43 -1
- package/src/plugins/sandbox/index.ts +10 -1
- package/src/plugins/sandbox/types.ts +78 -1
- package/src/plugins/scheduler/node.ts +13 -1
- package/src/plugins/scheduler/types.ts +2 -0
- package/src/plugins/types.ts +39 -2
- package/src/query.ts +29 -37
- package/src/scheduler-health.ts +46 -0
- package/src/schema/registry.ts +777 -255
- package/src/schema/types.ts +50 -8
- package/src/schema/url-pattern.ts +33 -0
- package/src/schema/zod-generator.ts +77 -5
- package/src/search/fts-manager.ts +117 -76
- package/src/search/query.ts +32 -11
- package/src/search/types.ts +2 -0
- package/src/seed/apply.ts +68 -15
- package/src/seed/types.ts +11 -3
- package/src/seed/validate.ts +52 -2
- package/src/taxonomies/index.ts +77 -75
- package/src/taxonomies/term-counts.ts +21 -8
- package/src/utils/slugify.ts +1 -29
- package/src/virtual-modules.d.ts +16 -0
- package/dist/adapters-BMyNSSZi.d.mts.map +0 -1
- package/dist/api-D2hunekQ.mjs.map +0 -1
- package/dist/apply-kwNEJW2l.mjs.map +0 -1
- package/dist/config-DyF3OKg_.mjs.map +0 -1
- package/dist/content-CJ94NEx5.mjs.map +0 -1
- package/dist/content-refresh-Xw7aKmou.mjs +0 -1629
- package/dist/content-refresh-Xw7aKmou.mjs.map +0 -1
- package/dist/context-C_1nrqnW.mjs.map +0 -1
- package/dist/dashboard-DINnNVVU.mjs.map +0 -1
- package/dist/errors-BucQ8VYz.mjs.map +0 -1
- package/dist/fts-manager-BITakW_R.mjs.map +0 -1
- package/dist/index-M37iz29I.d.mts.map +0 -1
- package/dist/index-MGw47uWq.d.mts.map +0 -1
- package/dist/loader-CGugY7Zl.mjs.map +0 -1
- package/dist/media-OhYL-7Io.mjs.map +0 -1
- package/dist/media-allowlist-D-peH1H5.mjs.map +0 -1
- package/dist/media-usage-BlxfTkN0.mjs.map +0 -1
- package/dist/menus-Y54RDPIN.mjs.map +0 -1
- package/dist/options-CA4eVX6P.d.mts.map +0 -1
- package/dist/query-C5w7PsRQ.mjs.map +0 -1
- package/dist/redirects-G8wAhWAf.mjs.map +0 -1
- package/dist/registry-Dbodb4Uo.mjs +0 -840
- package/dist/registry-Dbodb4Uo.mjs.map +0 -1
- package/dist/relations-G2ta7GIl.d.mts.map +0 -1
- package/dist/runner-BFTrkYhu.mjs.map +0 -1
- package/dist/search-FZhx5dDU.mjs.map +0 -1
- package/dist/seo-CobNfOvb.mjs.map +0 -1
- package/dist/slugify-C_tqlU4G.mjs +0 -30
- package/dist/slugify-C_tqlU4G.mjs.map +0 -1
- package/dist/taxonomies-CKuaZER5.mjs.map +0 -1
- package/dist/taxonomies-CLN1N92E.mjs.map +0 -1
- package/dist/taxonomy-pOrB2kZe.mjs.map +0 -1
- package/dist/types-BGWPMiBO.d.mts.map +0 -1
- package/dist/types-BnFP1M3J.d.mts.map +0 -1
- package/dist/types-Cd8iuS1J.mjs.map +0 -1
- package/dist/types-Cz8hNch2.d.mts.map +0 -1
- package/dist/types-Dc4ntQjQ.d.mts.map +0 -1
- package/dist/types-NBI3rF-_.mjs.map +0 -1
- package/dist/validate-C3oSmA7F.d.mts.map +0 -1
- package/dist/validate-mKo3RxBM.mjs.map +0 -1
- package/dist/version-C4PnpmoV.mjs +0 -7
- package/dist/zod-generator-CG64Hnbh.mjs.map +0 -1
- /package/dist/{api-tokens-Dai9dND0.mjs → api-tokens-CyTsLszZ.mjs} +0 -0
- /package/dist/{ssrf-Cj568Dgs.mjs → ssrf-DpXgKsna.mjs} +0 -0
- /package/dist/{types-DKuWPYV5.mjs → types-CP1CflWf.mjs} +0 -0
package/src/schema/registry.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ColumnDataType,
|
|
3
|
+
CreateTableBuilder,
|
|
4
|
+
Insertable,
|
|
5
|
+
Kysely,
|
|
6
|
+
Selectable,
|
|
7
|
+
Updateable,
|
|
8
|
+
} from "kysely";
|
|
2
9
|
import { sql } from "kysely";
|
|
3
10
|
import { ulid } from "ulidx";
|
|
4
11
|
|
|
@@ -6,14 +13,27 @@ import { currentTimestamp, listTablesLike, tableExists } from "../database/diale
|
|
|
6
13
|
import { withTransaction } from "../database/transaction.js";
|
|
7
14
|
import type { CollectionTable, Database, FieldTable } from "../database/types.js";
|
|
8
15
|
import { validateIdentifier } from "../database/validate.js";
|
|
16
|
+
import {
|
|
17
|
+
canResumeMediaUsageCollectionCapture,
|
|
18
|
+
finalizeMediaUsageCollectionCapture,
|
|
19
|
+
installPreparedMediaUsageCollectionCapture,
|
|
20
|
+
markMediaUsageCollectionCaptureReady,
|
|
21
|
+
prepareMediaUsageCollectionCapture,
|
|
22
|
+
} from "../media/usage/activation.js";
|
|
23
|
+
import {
|
|
24
|
+
deleteActivatedMediaUsageCollection,
|
|
25
|
+
isMediaUsageCollectionSlugDeleting,
|
|
26
|
+
} from "../media/usage/collection-deletion.js";
|
|
9
27
|
import {
|
|
10
28
|
deleteContentMediaUsageCollection,
|
|
29
|
+
invalidateContentMediaUsageSchemaChange,
|
|
11
30
|
markContentMediaUsageCollectionStaleSafely,
|
|
12
31
|
} from "../media/usage/content-refresh.js";
|
|
13
32
|
import { FTSManager } from "../search/fts-manager.js";
|
|
14
33
|
import { chunks, SQL_BATCH_SIZE } from "../utils/chunks.js";
|
|
15
34
|
import {
|
|
16
35
|
type Collection,
|
|
36
|
+
type CollectionAdminConfig,
|
|
17
37
|
type CollectionSource,
|
|
18
38
|
type CollectionSupport,
|
|
19
39
|
type ColumnType,
|
|
@@ -25,6 +45,7 @@ import {
|
|
|
25
45
|
type CollectionWithFields,
|
|
26
46
|
type FieldType,
|
|
27
47
|
FIELD_TYPE_TO_COLUMN,
|
|
48
|
+
isIndexableFieldType,
|
|
28
49
|
RESERVED_FIELD_SLUGS,
|
|
29
50
|
RESERVED_COLLECTION_SLUGS,
|
|
30
51
|
} from "./types.js";
|
|
@@ -35,6 +56,7 @@ const EC_PREFIX_PATTERN = /^ec_/;
|
|
|
35
56
|
const SINGLE_QUOTE_PATTERN = /'/g;
|
|
36
57
|
const UNDERSCORE_PATTERN = /_/g;
|
|
37
58
|
const WORD_BOUNDARY_PATTERN = /\b\w/g;
|
|
59
|
+
const FIELD_ID_PATTERN = /^[0-9A-Z]{26}$/;
|
|
38
60
|
|
|
39
61
|
/** Valid column types for runtime validation */
|
|
40
62
|
const COLUMN_TYPES: ReadonlySet<string> = new Set(["TEXT", "REAL", "INTEGER", "JSON"]);
|
|
@@ -44,6 +66,10 @@ const COLUMN_TYPE_TO_DATA_TYPE = {
|
|
|
44
66
|
INTEGER: "integer",
|
|
45
67
|
JSON: "json",
|
|
46
68
|
} satisfies Record<ColumnType, ColumnDataType>;
|
|
69
|
+
const TEXT_ALIAS_FIELD_TYPES: ReadonlySet<FieldType> = new Set(["string", "text", "slug"]);
|
|
70
|
+
|
|
71
|
+
/** Field types usable as a `titleField` — plain text that reads well as a title. */
|
|
72
|
+
const TITLE_FIELD_TYPES: ReadonlySet<string> = new Set(["string", "text", "slug"]);
|
|
47
73
|
|
|
48
74
|
/** Valid collection source prefixes/values */
|
|
49
75
|
const VALID_SOURCES: ReadonlySet<string> = new Set(["manual", "discovered", "seed"]);
|
|
@@ -69,7 +95,7 @@ const VALID_COLLECTION_SUPPORTS: ReadonlySet<string> = new Set<CollectionSupport
|
|
|
69
95
|
"seo",
|
|
70
96
|
]);
|
|
71
97
|
|
|
72
|
-
// Each _emdash_fields row uses
|
|
98
|
+
// Each _emdash_fields row uses 16 bound parameters. Six rows keep every
|
|
73
99
|
// multi-row INSERT below D1's 100-parameter statement limit.
|
|
74
100
|
const SEED_FIELD_INSERT_BATCH_SIZE = 6;
|
|
75
101
|
|
|
@@ -86,6 +112,15 @@ const UNORDERED_COLLECTION_RANK = 2147483647;
|
|
|
86
112
|
*/
|
|
87
113
|
const collectionOrder = sql<number>`coalesce(sort_order, ${sql.lit(UNORDERED_COLLECTION_RANK)})`;
|
|
88
114
|
|
|
115
|
+
function assertIndexableField(type: FieldType, indexed: boolean | undefined, slug: string): void {
|
|
116
|
+
if (indexed && !isIndexableFieldType(type)) {
|
|
117
|
+
throw new SchemaError(
|
|
118
|
+
`Field "${slug}" cannot be indexed because type "${type}" is not a scalar query type`,
|
|
119
|
+
"FIELD_NOT_INDEXABLE",
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
89
124
|
function isCollectionSupport(value: unknown): value is CollectionSupport {
|
|
90
125
|
return typeof value === "string" && VALID_COLLECTION_SUPPORTS.has(value);
|
|
91
126
|
}
|
|
@@ -105,6 +140,87 @@ function parseSupports(raw: string | null | undefined): CollectionSupport[] {
|
|
|
105
140
|
return parsed.filter(isCollectionSupport);
|
|
106
141
|
}
|
|
107
142
|
|
|
143
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
144
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function parseCollectionAdmin(raw: string | null | undefined): CollectionAdminConfig | undefined {
|
|
148
|
+
if (!raw) return undefined;
|
|
149
|
+
const parsed: unknown = JSON.parse(raw);
|
|
150
|
+
if (!isRecord(parsed)) return undefined;
|
|
151
|
+
const listColumns = parsed.listColumns;
|
|
152
|
+
return {
|
|
153
|
+
listColumns: Array.isArray(listColumns)
|
|
154
|
+
? listColumns.filter((value): value is string => typeof value === "string")
|
|
155
|
+
: undefined,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function buildSeedCollectionCaptureFingerprint(
|
|
160
|
+
input: Omit<CreateCollectionInput, "source">,
|
|
161
|
+
fields: readonly CreateFieldInput[],
|
|
162
|
+
): Promise<string> {
|
|
163
|
+
const supports = input.supports ?? ["drafts", "revisions"];
|
|
164
|
+
const hasSeo = input.hasSeo ?? supports.includes("seo") ?? false;
|
|
165
|
+
let maxSortOrder = -1;
|
|
166
|
+
const definitions = fields.map((field) => {
|
|
167
|
+
const sortOrder = field.sortOrder ?? maxSortOrder + 1;
|
|
168
|
+
maxSortOrder = Math.max(maxSortOrder, sortOrder);
|
|
169
|
+
return {
|
|
170
|
+
slug: field.slug,
|
|
171
|
+
label: field.label,
|
|
172
|
+
type: field.type,
|
|
173
|
+
required: field.required ?? false,
|
|
174
|
+
unique: field.unique ?? false,
|
|
175
|
+
defaultValue: field.defaultValue === undefined ? null : JSON.stringify(field.defaultValue),
|
|
176
|
+
validation: field.validation ? JSON.stringify(field.validation) : null,
|
|
177
|
+
widget: field.widget ?? null,
|
|
178
|
+
options: field.options ? JSON.stringify(field.options) : null,
|
|
179
|
+
sortOrder,
|
|
180
|
+
searchable: field.searchable ?? false,
|
|
181
|
+
translatable: field.translatable ?? true,
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
const payload = JSON.stringify(
|
|
185
|
+
canonicalizeFingerprintValue({
|
|
186
|
+
version: 1,
|
|
187
|
+
collection: {
|
|
188
|
+
slug: input.slug,
|
|
189
|
+
label: input.label,
|
|
190
|
+
labelSingular: input.labelSingular ?? null,
|
|
191
|
+
description: input.description ?? null,
|
|
192
|
+
icon: input.icon ?? null,
|
|
193
|
+
admin: input.admin ?? null,
|
|
194
|
+
supports,
|
|
195
|
+
hasSeo,
|
|
196
|
+
hidden: input.hidden ?? false,
|
|
197
|
+
sortOrder: input.sortOrder ?? null,
|
|
198
|
+
commentsEnabled: input.commentsEnabled ?? false,
|
|
199
|
+
urlPattern: input.urlPattern ?? null,
|
|
200
|
+
routable: input.routable ?? true,
|
|
201
|
+
},
|
|
202
|
+
fields: definitions,
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
|
|
206
|
+
const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
207
|
+
"",
|
|
208
|
+
);
|
|
209
|
+
return `media-usage-seed:v1:sha256:${hex}`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function canonicalizeFingerprintValue(value: unknown): unknown {
|
|
213
|
+
if (value === undefined) return { __emdashUndefined: true };
|
|
214
|
+
if (Array.isArray(value)) return value.map(canonicalizeFingerprintValue);
|
|
215
|
+
if (typeof value !== "object" || value === null) return value;
|
|
216
|
+
|
|
217
|
+
const canonical: Record<string, unknown> = {};
|
|
218
|
+
for (const [key, entry] of Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
219
|
+
canonical[key] = canonicalizeFingerprintValue(entry);
|
|
220
|
+
}
|
|
221
|
+
return canonical;
|
|
222
|
+
}
|
|
223
|
+
|
|
108
224
|
/**
|
|
109
225
|
* Error thrown when a schema operation fails
|
|
110
226
|
*/
|
|
@@ -227,6 +343,61 @@ export class SchemaRegistry {
|
|
|
227
343
|
}));
|
|
228
344
|
}
|
|
229
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Validate `titleField`/`dateField` against the collection's fields:
|
|
348
|
+
* `titleField` must be a text-like field; `dateField` must be a `datetime` field.
|
|
349
|
+
* Only truthy values are checked (undefined = unchanged, null/"" = cleared).
|
|
350
|
+
*/
|
|
351
|
+
private async validateTitleDateFields(
|
|
352
|
+
collectionId: string,
|
|
353
|
+
collectionSlug: string,
|
|
354
|
+
input: { titleField?: string | null; dateField?: string | null },
|
|
355
|
+
db: Kysely<Database> = this.db,
|
|
356
|
+
): Promise<void> {
|
|
357
|
+
const slugs = [input.titleField, input.dateField].filter((slug): slug is string => !!slug);
|
|
358
|
+
if (slugs.length === 0) return;
|
|
359
|
+
|
|
360
|
+
const rows = await db
|
|
361
|
+
.selectFrom("_emdash_fields")
|
|
362
|
+
.where("collection_id", "=", collectionId)
|
|
363
|
+
.where("slug", "in", slugs)
|
|
364
|
+
.select(["slug", "type"])
|
|
365
|
+
.execute();
|
|
366
|
+
const typeBySlug = new Map(rows.map((row) => [row.slug, row.type]));
|
|
367
|
+
|
|
368
|
+
if (input.titleField) {
|
|
369
|
+
const type = typeBySlug.get(input.titleField);
|
|
370
|
+
if (type === undefined) {
|
|
371
|
+
throw new SchemaError(
|
|
372
|
+
`titleField "${input.titleField}" is not a field on "${collectionSlug}"`,
|
|
373
|
+
"INVALID_TITLE_FIELD",
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (!TITLE_FIELD_TYPES.has(type)) {
|
|
377
|
+
throw new SchemaError(
|
|
378
|
+
`titleField "${input.titleField}" must be a text field (got "${type}")`,
|
|
379
|
+
"INVALID_TITLE_FIELD",
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (input.dateField) {
|
|
385
|
+
const type = typeBySlug.get(input.dateField);
|
|
386
|
+
if (type === undefined) {
|
|
387
|
+
throw new SchemaError(
|
|
388
|
+
`dateField "${input.dateField}" is not a field on "${collectionSlug}"`,
|
|
389
|
+
"INVALID_DATE_FIELD",
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
if (type !== "datetime") {
|
|
393
|
+
throw new SchemaError(
|
|
394
|
+
`dateField "${input.dateField}" must be a datetime field (got "${type}")`,
|
|
395
|
+
"INVALID_DATE_FIELD",
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
230
401
|
/**
|
|
231
402
|
* Create a new collection
|
|
232
403
|
*/
|
|
@@ -236,14 +407,26 @@ export class SchemaRegistry {
|
|
|
236
407
|
if (RESERVED_COLLECTION_SLUGS.includes(input.slug)) {
|
|
237
408
|
throw new SchemaError(`Collection slug "${input.slug}" is reserved`, "RESERVED_SLUG");
|
|
238
409
|
}
|
|
410
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, input.slug)) {
|
|
411
|
+
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
412
|
+
}
|
|
239
413
|
|
|
240
414
|
// Check if collection already exists
|
|
241
415
|
const existing = await this.getCollection(input.slug);
|
|
242
|
-
if (
|
|
416
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, input.slug)) {
|
|
417
|
+
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
418
|
+
}
|
|
419
|
+
if (
|
|
420
|
+
existing &&
|
|
421
|
+
!(await canResumeMediaUsageCollectionCapture(this.db, {
|
|
422
|
+
collectionId: existing.id,
|
|
423
|
+
collectionSlug: existing.slug,
|
|
424
|
+
}))
|
|
425
|
+
) {
|
|
243
426
|
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
244
427
|
}
|
|
245
428
|
|
|
246
|
-
const
|
|
429
|
+
const proposedId = existing?.id ?? ulid();
|
|
247
430
|
|
|
248
431
|
// Default `supports` to drafts + revisions when the caller didn't
|
|
249
432
|
// specify it. Explicit empty array (`[]`) is preserved as an opt-out
|
|
@@ -259,26 +442,52 @@ export class SchemaRegistry {
|
|
|
259
442
|
const hasSeo = input.hasSeo ?? supports.includes("seo") ?? false;
|
|
260
443
|
|
|
261
444
|
await withTransaction(this.db, async (trx) => {
|
|
262
|
-
await trx
|
|
263
|
-
|
|
264
|
-
.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
.
|
|
445
|
+
const capture = await prepareMediaUsageCollectionCapture(trx, {
|
|
446
|
+
collectionId: proposedId,
|
|
447
|
+
collectionSlug: input.slug,
|
|
448
|
+
registeredCollectionId: existing?.id,
|
|
449
|
+
});
|
|
450
|
+
const values: Insertable<CollectionTable> = {
|
|
451
|
+
id: capture.collectionId,
|
|
452
|
+
slug: input.slug,
|
|
453
|
+
label: input.label,
|
|
454
|
+
label_singular: input.labelSingular ?? null,
|
|
455
|
+
description: input.description ?? null,
|
|
456
|
+
icon: input.icon ?? null,
|
|
457
|
+
admin_config: input.admin ? JSON.stringify(input.admin) : null,
|
|
458
|
+
supports: JSON.stringify(supports),
|
|
459
|
+
source: input.source ?? "manual",
|
|
460
|
+
has_seo: hasSeo ? 1 : 0,
|
|
461
|
+
routable: input.routable === false ? 0 : 1,
|
|
462
|
+
hidden: input.hidden ? 1 : 0,
|
|
463
|
+
sort_order: input.sortOrder ?? null,
|
|
464
|
+
comments_enabled: input.commentsEnabled ? 1 : 0,
|
|
465
|
+
url_pattern: input.urlPattern ?? null,
|
|
466
|
+
};
|
|
280
467
|
|
|
281
|
-
|
|
468
|
+
if (capture.captureRequired) {
|
|
469
|
+
await this.createContentTable(input.slug, trx, [], {
|
|
470
|
+
ifNotExists: capture.resuming,
|
|
471
|
+
});
|
|
472
|
+
await installPreparedMediaUsageCollectionCapture(trx, {
|
|
473
|
+
collectionId: capture.collectionId,
|
|
474
|
+
collectionSlug: input.slug,
|
|
475
|
+
});
|
|
476
|
+
await markMediaUsageCollectionCaptureReady(trx, {
|
|
477
|
+
collectionId: capture.collectionId,
|
|
478
|
+
collectionSlug: input.slug,
|
|
479
|
+
});
|
|
480
|
+
if (!capture.registrationExists) {
|
|
481
|
+
await trx.insertInto("_emdash_collections").values(values).execute();
|
|
482
|
+
}
|
|
483
|
+
await finalizeMediaUsageCollectionCapture(trx, {
|
|
484
|
+
collectionId: capture.collectionId,
|
|
485
|
+
collectionSlug: input.slug,
|
|
486
|
+
});
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
await trx.insertInto("_emdash_collections").values(values).execute();
|
|
282
491
|
await this.createContentTable(input.slug, trx);
|
|
283
492
|
});
|
|
284
493
|
|
|
@@ -308,15 +517,14 @@ export class SchemaRegistry {
|
|
|
308
517
|
if (RESERVED_COLLECTION_SLUGS.includes(input.slug)) {
|
|
309
518
|
throw new SchemaError(`Collection slug "${input.slug}" is reserved`, "RESERVED_SLUG");
|
|
310
519
|
}
|
|
311
|
-
|
|
312
|
-
const existing = await this.getCollection(input.slug);
|
|
313
|
-
if (existing) {
|
|
520
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, input.slug)) {
|
|
314
521
|
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
315
522
|
}
|
|
316
523
|
|
|
317
524
|
const fieldSlugs = new Set<string>();
|
|
318
525
|
for (const field of fields) {
|
|
319
526
|
this.validateSlug(field.slug, "field");
|
|
527
|
+
assertIndexableField(field.type, field.indexed, field.slug);
|
|
320
528
|
if (RESERVED_FIELD_SLUGS.includes(field.slug)) {
|
|
321
529
|
throw new SchemaError(`Field slug "${field.slug}" is reserved`, "RESERVED_SLUG");
|
|
322
530
|
}
|
|
@@ -329,9 +537,25 @@ export class SchemaRegistry {
|
|
|
329
537
|
fieldSlugs.add(field.slug);
|
|
330
538
|
}
|
|
331
539
|
|
|
332
|
-
const collectionId = ulid();
|
|
333
540
|
const supports = input.supports ?? ["drafts", "revisions"];
|
|
334
541
|
const hasSeo = input.hasSeo ?? supports.includes("seo") ?? false;
|
|
542
|
+
const creationFingerprint = await buildSeedCollectionCaptureFingerprint(input, fields);
|
|
543
|
+
const existing = await this.getCollection(input.slug);
|
|
544
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, input.slug)) {
|
|
545
|
+
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
546
|
+
}
|
|
547
|
+
if (
|
|
548
|
+
existing &&
|
|
549
|
+
!(await canResumeMediaUsageCollectionCapture(this.db, {
|
|
550
|
+
collectionId: existing.id,
|
|
551
|
+
collectionSlug: existing.slug,
|
|
552
|
+
creationFingerprint,
|
|
553
|
+
}))
|
|
554
|
+
) {
|
|
555
|
+
throw new SchemaError(`Collection "${input.slug}" already exists`, "COLLECTION_EXISTS");
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const proposedCollectionId = existing?.id ?? ulid();
|
|
335
559
|
let maxSortOrder = -1;
|
|
336
560
|
const fieldRows: Insertable<FieldTable>[] = fields.map((field) => {
|
|
337
561
|
const sortOrder = field.sortOrder ?? maxSortOrder + 1;
|
|
@@ -339,7 +563,7 @@ export class SchemaRegistry {
|
|
|
339
563
|
|
|
340
564
|
return {
|
|
341
565
|
id: ulid(),
|
|
342
|
-
collection_id:
|
|
566
|
+
collection_id: proposedCollectionId,
|
|
343
567
|
slug: field.slug,
|
|
344
568
|
label: field.label,
|
|
345
569
|
type: field.type,
|
|
@@ -352,6 +576,7 @@ export class SchemaRegistry {
|
|
|
352
576
|
options: field.options ? JSON.stringify(field.options) : null,
|
|
353
577
|
sort_order: sortOrder,
|
|
354
578
|
searchable: field.searchable ? 1 : 0,
|
|
579
|
+
indexed: field.indexed ? 1 : 0,
|
|
355
580
|
translatable: field.translatable === false ? 0 : 1,
|
|
356
581
|
};
|
|
357
582
|
});
|
|
@@ -359,30 +584,79 @@ export class SchemaRegistry {
|
|
|
359
584
|
let schemaMutated = false;
|
|
360
585
|
try {
|
|
361
586
|
await withTransaction(this.db, async (trx) => {
|
|
362
|
-
await trx
|
|
363
|
-
|
|
364
|
-
.
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
.
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
587
|
+
const capture = await prepareMediaUsageCollectionCapture(trx, {
|
|
588
|
+
collectionId: proposedCollectionId,
|
|
589
|
+
collectionSlug: input.slug,
|
|
590
|
+
creationFingerprint,
|
|
591
|
+
registeredCollectionId: existing?.id,
|
|
592
|
+
});
|
|
593
|
+
const collectionValues: Insertable<CollectionTable> = {
|
|
594
|
+
id: capture.collectionId,
|
|
595
|
+
slug: input.slug,
|
|
596
|
+
label: input.label,
|
|
597
|
+
label_singular: input.labelSingular ?? null,
|
|
598
|
+
description: input.description ?? null,
|
|
599
|
+
icon: input.icon ?? null,
|
|
600
|
+
admin_config: input.admin ? JSON.stringify(input.admin) : null,
|
|
601
|
+
supports: JSON.stringify(supports),
|
|
602
|
+
source: "seed",
|
|
603
|
+
has_seo: hasSeo ? 1 : 0,
|
|
604
|
+
routable: input.routable === false ? 0 : 1,
|
|
605
|
+
hidden: input.hidden ? 1 : 0,
|
|
606
|
+
sort_order: input.sortOrder ?? null,
|
|
607
|
+
comments_enabled: input.commentsEnabled ? 1 : 0,
|
|
608
|
+
url_pattern: input.urlPattern ?? null,
|
|
609
|
+
};
|
|
610
|
+
const rows = fieldRows.map((row) => ({
|
|
611
|
+
...row,
|
|
612
|
+
collection_id: capture.collectionId,
|
|
613
|
+
}));
|
|
614
|
+
|
|
615
|
+
if (capture.captureRequired) {
|
|
616
|
+
await this.createContentTable(input.slug, trx, fields, {
|
|
617
|
+
ifNotExists: capture.resuming,
|
|
618
|
+
});
|
|
619
|
+
await installPreparedMediaUsageCollectionCapture(trx, {
|
|
620
|
+
collectionId: capture.collectionId,
|
|
621
|
+
collectionSlug: input.slug,
|
|
622
|
+
});
|
|
623
|
+
await markMediaUsageCollectionCaptureReady(trx, {
|
|
624
|
+
collectionId: capture.collectionId,
|
|
625
|
+
collectionSlug: input.slug,
|
|
626
|
+
});
|
|
627
|
+
if (!capture.registrationExists) {
|
|
628
|
+
await trx.insertInto("_emdash_collections").values(collectionValues).execute();
|
|
629
|
+
schemaMutated = true;
|
|
630
|
+
}
|
|
631
|
+
} else {
|
|
632
|
+
await trx.insertInto("_emdash_collections").values(collectionValues).execute();
|
|
633
|
+
schemaMutated = true;
|
|
634
|
+
await this.createContentTable(input.slug, trx, fields);
|
|
635
|
+
}
|
|
383
636
|
|
|
384
|
-
for (const fieldBatch of chunks(
|
|
385
|
-
|
|
637
|
+
for (const fieldBatch of chunks(rows, SEED_FIELD_INSERT_BATCH_SIZE)) {
|
|
638
|
+
let insert = trx.insertInto("_emdash_fields").values(fieldBatch);
|
|
639
|
+
if (capture.resuming) {
|
|
640
|
+
insert = insert.onConflict((conflict) =>
|
|
641
|
+
conflict.columns(["collection_id", "slug"]).doNothing(),
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
await insert.execute();
|
|
645
|
+
}
|
|
646
|
+
let indexedRows: readonly { id: string; slug: string; indexed?: number }[] = rows;
|
|
647
|
+
if (capture.resuming) {
|
|
648
|
+
indexedRows = await this.assertSeedFieldDefinitions(capture.collectionId, fields, trx);
|
|
649
|
+
}
|
|
650
|
+
for (const field of indexedRows) {
|
|
651
|
+
if (field.indexed === 1) {
|
|
652
|
+
await this.createFieldIndex(input.slug, field.id, field.slug, trx);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (capture.captureRequired) {
|
|
656
|
+
await finalizeMediaUsageCollectionCapture(trx, {
|
|
657
|
+
collectionId: capture.collectionId,
|
|
658
|
+
collectionSlug: input.slug,
|
|
659
|
+
});
|
|
386
660
|
}
|
|
387
661
|
});
|
|
388
662
|
|
|
@@ -399,69 +673,108 @@ export class SchemaRegistry {
|
|
|
399
673
|
}
|
|
400
674
|
}
|
|
401
675
|
|
|
676
|
+
private async assertSeedFieldDefinitions(
|
|
677
|
+
collectionId: string,
|
|
678
|
+
fields: readonly CreateFieldInput[],
|
|
679
|
+
db: Kysely<Database>,
|
|
680
|
+
): Promise<Selectable<FieldTable>[]> {
|
|
681
|
+
const stored = await db
|
|
682
|
+
.selectFrom("_emdash_fields")
|
|
683
|
+
.selectAll()
|
|
684
|
+
.where("collection_id", "=", collectionId)
|
|
685
|
+
.execute();
|
|
686
|
+
if (stored.length !== fields.length) {
|
|
687
|
+
throw new SchemaError("Interrupted seed collection fields do not match", "CREATE_FAILED");
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
let maxSortOrder = -1;
|
|
691
|
+
for (const field of fields) {
|
|
692
|
+
const sortOrder = field.sortOrder ?? maxSortOrder + 1;
|
|
693
|
+
maxSortOrder = Math.max(maxSortOrder, sortOrder);
|
|
694
|
+
const row = stored.find((candidate) => candidate.slug === field.slug);
|
|
695
|
+
if (
|
|
696
|
+
!row ||
|
|
697
|
+
row.label !== field.label ||
|
|
698
|
+
row.type !== field.type ||
|
|
699
|
+
row.column_type !== FIELD_TYPE_TO_COLUMN[field.type] ||
|
|
700
|
+
row.required !== (field.required ? 1 : 0) ||
|
|
701
|
+
row.unique !== (field.unique ? 1 : 0) ||
|
|
702
|
+
row.default_value !==
|
|
703
|
+
(field.defaultValue !== undefined ? JSON.stringify(field.defaultValue) : null) ||
|
|
704
|
+
row.validation !== (field.validation ? JSON.stringify(field.validation) : null) ||
|
|
705
|
+
row.widget !== (field.widget ?? null) ||
|
|
706
|
+
row.options !== (field.options ? JSON.stringify(field.options) : null) ||
|
|
707
|
+
row.sort_order !== sortOrder ||
|
|
708
|
+
row.searchable !== (field.searchable ? 1 : 0) ||
|
|
709
|
+
row.indexed !== (field.indexed ? 1 : 0) ||
|
|
710
|
+
row.translatable !== (field.translatable === false ? 0 : 1)
|
|
711
|
+
) {
|
|
712
|
+
throw new SchemaError("Interrupted seed collection fields do not match", "CREATE_FAILED");
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return stored;
|
|
716
|
+
}
|
|
717
|
+
|
|
402
718
|
/**
|
|
403
719
|
* Update a collection
|
|
404
720
|
*/
|
|
405
721
|
async updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection> {
|
|
406
|
-
const existing = await this.getCollection(slug);
|
|
407
|
-
if (!existing) {
|
|
408
|
-
throw new SchemaError(`Collection "${slug}" not found`, "COLLECTION_NOT_FOUND");
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const now = new Date().toISOString();
|
|
412
|
-
|
|
413
|
-
// Derive hasSeo from supports array if supports is being updated and hasSeo not explicitly set
|
|
414
|
-
const supportsArray = input.supports ?? existing.supports;
|
|
415
|
-
const hasSeo =
|
|
416
|
-
input.hasSeo !== undefined
|
|
417
|
-
? input.hasSeo
|
|
418
|
-
: input.supports !== undefined
|
|
419
|
-
? supportsArray.includes("seo")
|
|
420
|
-
: existing.hasSeo;
|
|
421
|
-
|
|
422
722
|
return withTransaction(this.db, async (trx) => {
|
|
723
|
+
const existingRow = await trx
|
|
724
|
+
.selectFrom("_emdash_collections")
|
|
725
|
+
.where("slug", "=", slug)
|
|
726
|
+
.selectAll()
|
|
727
|
+
.executeTakeFirst();
|
|
728
|
+
if (!existingRow) {
|
|
729
|
+
throw new SchemaError(`Collection "${slug}" not found`, "COLLECTION_NOT_FOUND");
|
|
730
|
+
}
|
|
731
|
+
const existing = this.mapCollectionRow(existingRow);
|
|
732
|
+
await this.validateTitleDateFields(
|
|
733
|
+
existing.id,
|
|
734
|
+
slug,
|
|
735
|
+
{
|
|
736
|
+
titleField: input.titleField,
|
|
737
|
+
dateField: input.dateField,
|
|
738
|
+
},
|
|
739
|
+
trx,
|
|
740
|
+
);
|
|
741
|
+
const updates: Updateable<CollectionTable> = {};
|
|
742
|
+
|
|
743
|
+
if (input.label !== undefined) updates.label = input.label;
|
|
744
|
+
if (input.labelSingular !== undefined) updates.label_singular = input.labelSingular;
|
|
745
|
+
if (input.description !== undefined) updates.description = input.description;
|
|
746
|
+
if (input.icon !== undefined) updates.icon = input.icon;
|
|
747
|
+
if (input.admin !== undefined) updates.admin_config = JSON.stringify(input.admin);
|
|
748
|
+
if (input.supports !== undefined) updates.supports = JSON.stringify(input.supports);
|
|
749
|
+
if (input.urlPattern !== undefined) updates.url_pattern = input.urlPattern;
|
|
750
|
+
if (input.routable !== undefined) updates.routable = input.routable ? 1 : 0;
|
|
751
|
+
if (input.hasSeo !== undefined) {
|
|
752
|
+
updates.has_seo = input.hasSeo ? 1 : 0;
|
|
753
|
+
} else if (input.supports !== undefined) {
|
|
754
|
+
updates.has_seo = input.supports.includes("seo") ? 1 : 0;
|
|
755
|
+
}
|
|
756
|
+
if (input.hidden !== undefined) updates.hidden = input.hidden ? 1 : 0;
|
|
757
|
+
if (input.sortOrder !== undefined) updates.sort_order = input.sortOrder;
|
|
758
|
+
if (input.titleField !== undefined) updates.title_field = input.titleField || null;
|
|
759
|
+
if (input.dateField !== undefined) updates.date_field = input.dateField || null;
|
|
760
|
+
if (input.commentsEnabled !== undefined) {
|
|
761
|
+
updates.comments_enabled = input.commentsEnabled ? 1 : 0;
|
|
762
|
+
}
|
|
763
|
+
if (input.commentsModeration !== undefined) {
|
|
764
|
+
updates.comments_moderation = input.commentsModeration;
|
|
765
|
+
}
|
|
766
|
+
if (input.commentsClosedAfterDays !== undefined) {
|
|
767
|
+
updates.comments_closed_after_days = input.commentsClosedAfterDays;
|
|
768
|
+
}
|
|
769
|
+
if (input.commentsAutoApproveUsers !== undefined) {
|
|
770
|
+
updates.comments_auto_approve_users = input.commentsAutoApproveUsers ? 1 : 0;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
updates.updated_at = new Date().toISOString();
|
|
423
774
|
await trx
|
|
424
775
|
.updateTable("_emdash_collections")
|
|
425
|
-
.set(
|
|
426
|
-
|
|
427
|
-
label_singular: input.labelSingular ?? existing.labelSingular ?? null,
|
|
428
|
-
description: input.description ?? existing.description ?? null,
|
|
429
|
-
icon: input.icon ?? existing.icon ?? null,
|
|
430
|
-
supports: input.supports
|
|
431
|
-
? JSON.stringify(input.supports)
|
|
432
|
-
: JSON.stringify(existing.supports),
|
|
433
|
-
url_pattern:
|
|
434
|
-
input.urlPattern !== undefined
|
|
435
|
-
? (input.urlPattern ?? null)
|
|
436
|
-
: (existing.urlPattern ?? null),
|
|
437
|
-
has_seo: hasSeo ? 1 : 0,
|
|
438
|
-
hidden: input.hidden !== undefined ? (input.hidden ? 1 : 0) : existing.hidden ? 1 : 0,
|
|
439
|
-
sort_order:
|
|
440
|
-
input.sortOrder !== undefined ? input.sortOrder : (existing.sortOrder ?? null),
|
|
441
|
-
comments_enabled:
|
|
442
|
-
input.commentsEnabled !== undefined
|
|
443
|
-
? input.commentsEnabled
|
|
444
|
-
? 1
|
|
445
|
-
: 0
|
|
446
|
-
: existing.commentsEnabled
|
|
447
|
-
? 1
|
|
448
|
-
: 0,
|
|
449
|
-
comments_moderation: input.commentsModeration ?? existing.commentsModeration,
|
|
450
|
-
comments_closed_after_days:
|
|
451
|
-
input.commentsClosedAfterDays !== undefined
|
|
452
|
-
? input.commentsClosedAfterDays
|
|
453
|
-
: existing.commentsClosedAfterDays,
|
|
454
|
-
comments_auto_approve_users:
|
|
455
|
-
input.commentsAutoApproveUsers !== undefined
|
|
456
|
-
? input.commentsAutoApproveUsers
|
|
457
|
-
? 1
|
|
458
|
-
: 0
|
|
459
|
-
: existing.commentsAutoApproveUsers
|
|
460
|
-
? 1
|
|
461
|
-
: 0,
|
|
462
|
-
updated_at: now,
|
|
463
|
-
})
|
|
464
|
-
.where("slug", "=", slug)
|
|
776
|
+
.set(updates)
|
|
777
|
+
.where("id", "=", existing.id)
|
|
465
778
|
.execute();
|
|
466
779
|
|
|
467
780
|
const row = await trx
|
|
@@ -492,21 +805,31 @@ export class SchemaRegistry {
|
|
|
492
805
|
*/
|
|
493
806
|
async deleteCollection(slug: string, options?: { force?: boolean }): Promise<void> {
|
|
494
807
|
const existing = await this.getCollection(slug);
|
|
808
|
+
if (existing && !options?.force && (await this.collectionHasContent(slug))) {
|
|
809
|
+
throw new SchemaError(
|
|
810
|
+
`Collection "${slug}" has content. Use force: true to delete.`,
|
|
811
|
+
"COLLECTION_HAS_CONTENT",
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
const activated = await deleteActivatedMediaUsageCollection(this.db, {
|
|
815
|
+
collectionId: existing?.id,
|
|
816
|
+
collectionSlug: slug,
|
|
817
|
+
forceDelete: options?.force === true,
|
|
818
|
+
});
|
|
819
|
+
if (activated === "has_content") {
|
|
820
|
+
throw new SchemaError(
|
|
821
|
+
`Collection "${slug}" has content. Use force: true to delete.`,
|
|
822
|
+
"COLLECTION_HAS_CONTENT",
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
if (activated === "in_progress") {
|
|
826
|
+
throw new SchemaError(`Collection "${slug}" deletion is already in progress`, "CONFLICT");
|
|
827
|
+
}
|
|
828
|
+
if (activated === "deleted") return;
|
|
495
829
|
if (!existing) {
|
|
496
830
|
throw new SchemaError(`Collection "${slug}" not found`, "COLLECTION_NOT_FOUND");
|
|
497
831
|
}
|
|
498
832
|
|
|
499
|
-
// Check if collection has content
|
|
500
|
-
if (!options?.force) {
|
|
501
|
-
const hasContent = await this.collectionHasContent(slug);
|
|
502
|
-
if (hasContent) {
|
|
503
|
-
throw new SchemaError(
|
|
504
|
-
`Collection "${slug}" has content. Use force: true to delete.`,
|
|
505
|
-
"COLLECTION_HAS_CONTENT",
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
833
|
let contentTableDropped = false;
|
|
511
834
|
try {
|
|
512
835
|
await withTransaction(this.db, async (trx) => {
|
|
@@ -593,6 +916,7 @@ export class SchemaRegistry {
|
|
|
593
916
|
|
|
594
917
|
const id = ulid();
|
|
595
918
|
const columnType = FIELD_TYPE_TO_COLUMN[input.type];
|
|
919
|
+
assertIndexableField(input.type, input.indexed, input.slug);
|
|
596
920
|
|
|
597
921
|
// Get max sort order
|
|
598
922
|
const maxSort = await this.db
|
|
@@ -602,6 +926,10 @@ export class SchemaRegistry {
|
|
|
602
926
|
.executeTakeFirst();
|
|
603
927
|
|
|
604
928
|
const sortOrder = input.sortOrder ?? (maxSort?.max ?? -1) + 1;
|
|
929
|
+
const activeCoverageInvalidated = await invalidateContentMediaUsageSchemaChange(
|
|
930
|
+
this.db,
|
|
931
|
+
collectionSlug,
|
|
932
|
+
);
|
|
605
933
|
|
|
606
934
|
let schemaMutated = false;
|
|
607
935
|
try {
|
|
@@ -625,6 +953,7 @@ export class SchemaRegistry {
|
|
|
625
953
|
options: input.options ? JSON.stringify(input.options) : null,
|
|
626
954
|
sort_order: sortOrder,
|
|
627
955
|
searchable: input.searchable ? 1 : 0,
|
|
956
|
+
indexed: input.indexed ? 1 : 0,
|
|
628
957
|
translatable: input.translatable === false ? 0 : 1,
|
|
629
958
|
})
|
|
630
959
|
.execute();
|
|
@@ -642,6 +971,10 @@ export class SchemaRegistry {
|
|
|
642
971
|
trx,
|
|
643
972
|
);
|
|
644
973
|
|
|
974
|
+
if (input.indexed) {
|
|
975
|
+
await this.createFieldIndex(collectionSlug, id, input.slug, trx);
|
|
976
|
+
}
|
|
977
|
+
|
|
645
978
|
// Read the created field via trx (not this.db) to avoid connection mutex deadlock
|
|
646
979
|
const fieldRow = await trx
|
|
647
980
|
.selectFrom("_emdash_fields")
|
|
@@ -663,20 +996,28 @@ export class SchemaRegistry {
|
|
|
663
996
|
|
|
664
997
|
return field;
|
|
665
998
|
});
|
|
666
|
-
|
|
667
|
-
this.db,
|
|
668
|
-
|
|
669
|
-
"CONTENT_USAGE_STALE",
|
|
670
|
-
);
|
|
671
|
-
return created;
|
|
672
|
-
} catch (error) {
|
|
673
|
-
if (schemaMutated) {
|
|
999
|
+
if (activeCoverageInvalidated) {
|
|
1000
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1001
|
+
} else {
|
|
674
1002
|
await markContentMediaUsageCollectionStaleSafely(
|
|
675
1003
|
this.db,
|
|
676
1004
|
collectionSlug,
|
|
677
1005
|
"CONTENT_USAGE_STALE",
|
|
678
1006
|
);
|
|
679
1007
|
}
|
|
1008
|
+
return created;
|
|
1009
|
+
} catch (error) {
|
|
1010
|
+
if (schemaMutated) {
|
|
1011
|
+
if (activeCoverageInvalidated) {
|
|
1012
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1013
|
+
} else {
|
|
1014
|
+
await markContentMediaUsageCollectionStaleSafely(
|
|
1015
|
+
this.db,
|
|
1016
|
+
collectionSlug,
|
|
1017
|
+
"CONTENT_USAGE_STALE",
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
680
1021
|
throw error;
|
|
681
1022
|
}
|
|
682
1023
|
}
|
|
@@ -689,87 +1030,126 @@ export class SchemaRegistry {
|
|
|
689
1030
|
fieldSlug: string,
|
|
690
1031
|
input: UpdateFieldInput,
|
|
691
1032
|
): Promise<Field> {
|
|
692
|
-
|
|
693
|
-
if (!field) {
|
|
694
|
-
throw new SchemaError(
|
|
695
|
-
`Field "${fieldSlug}" not found in collection "${collectionSlug}"`,
|
|
696
|
-
"FIELD_NOT_FOUND",
|
|
697
|
-
);
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// `input.validation === undefined` means "no change" (keep existing);
|
|
701
|
-
// an explicit `null` clears the column.
|
|
702
|
-
const nextValidation = input.validation === undefined ? field.validation : input.validation;
|
|
703
|
-
|
|
704
|
-
// A field-type change is only safe when the underlying column type stays
|
|
705
|
-
// the same. There is no in-place column migration (only addColumn/
|
|
706
|
-
// dropColumn), so a change that would alter the SQLite column affinity
|
|
707
|
-
// (e.g. `text` TEXT -> `portableText` JSON) is rejected rather than
|
|
708
|
-
// silently rewriting only the metadata — which would leave `column_type`
|
|
709
|
-
// pointing at a column type the real `ec_*` column doesn't have (#1397).
|
|
710
|
-
let nextType = field.type;
|
|
711
|
-
let nextColumnType = field.columnType;
|
|
712
|
-
if (input.type !== undefined && input.type !== field.type) {
|
|
713
|
-
const newColumnType = FIELD_TYPE_TO_COLUMN[input.type];
|
|
714
|
-
if (newColumnType !== field.columnType) {
|
|
715
|
-
throw new SchemaError(
|
|
716
|
-
`Cannot change field "${fieldSlug}" in collection "${collectionSlug}" from type ` +
|
|
717
|
-
`"${field.type}" to "${input.type}": the underlying column type would change from ` +
|
|
718
|
-
`${field.columnType} to ${newColumnType}, which requires a manual content migration. ` +
|
|
719
|
-
`Drop and re-create the field, or migrate the column data, before changing its type.`,
|
|
720
|
-
"FIELD_TYPE_COLUMN_CHANGE",
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
nextType = input.type;
|
|
724
|
-
nextColumnType = newColumnType;
|
|
725
|
-
}
|
|
726
|
-
|
|
1033
|
+
let activeCoverageInvalidated = false;
|
|
727
1034
|
let schemaMutated = false;
|
|
728
1035
|
try {
|
|
729
1036
|
const updatedField = await withTransaction(this.db, async (trx) => {
|
|
730
|
-
await trx
|
|
731
|
-
.
|
|
732
|
-
.
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1037
|
+
const collectionRow = await trx
|
|
1038
|
+
.selectFrom("_emdash_collections")
|
|
1039
|
+
.where("slug", "=", collectionSlug)
|
|
1040
|
+
.select(["id", "title_field", "date_field"])
|
|
1041
|
+
.executeTakeFirst();
|
|
1042
|
+
const fieldRow = collectionRow
|
|
1043
|
+
? await trx
|
|
1044
|
+
.selectFrom("_emdash_fields")
|
|
1045
|
+
.where("collection_id", "=", collectionRow.id)
|
|
1046
|
+
.where("slug", "=", fieldSlug)
|
|
1047
|
+
.selectAll()
|
|
1048
|
+
.executeTakeFirst()
|
|
1049
|
+
: undefined;
|
|
1050
|
+
if (!fieldRow) {
|
|
1051
|
+
throw new SchemaError(
|
|
1052
|
+
`Field "${fieldSlug}" not found in collection "${collectionSlug}"`,
|
|
1053
|
+
"FIELD_NOT_FOUND",
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
const field = this.mapFieldRow(fieldRow);
|
|
1057
|
+
const updates: Updateable<FieldTable> = {};
|
|
1058
|
+
let nextType = field.type;
|
|
1059
|
+
|
|
1060
|
+
if (input.type !== undefined && input.type !== field.type) {
|
|
1061
|
+
const newColumnType = FIELD_TYPE_TO_COLUMN[input.type];
|
|
1062
|
+
if (newColumnType !== field.columnType) {
|
|
1063
|
+
throw new SchemaError(
|
|
1064
|
+
`Cannot change field "${fieldSlug}" in collection "${collectionSlug}" from type ` +
|
|
1065
|
+
`"${field.type}" to "${input.type}": the underlying column type would change from ` +
|
|
1066
|
+
`${field.columnType} to ${newColumnType}, which requires a manual content migration.`,
|
|
1067
|
+
"FIELD_TYPE_COLUMN_CHANGE",
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
if (!TEXT_ALIAS_FIELD_TYPES.has(field.type) || !TEXT_ALIAS_FIELD_TYPES.has(input.type)) {
|
|
1071
|
+
throw new SchemaError(
|
|
1072
|
+
`Cannot change field "${fieldSlug}" in collection "${collectionSlug}" from type ` +
|
|
1073
|
+
`"${field.type}" to "${input.type}" without a manual content migration.`,
|
|
1074
|
+
"FIELD_TYPE_CHANGE_REQUIRES_MIGRATION",
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
if (collectionRow?.title_field === fieldSlug && !TITLE_FIELD_TYPES.has(input.type)) {
|
|
1078
|
+
throw new SchemaError(
|
|
1079
|
+
`titleField "${fieldSlug}" must stay a text field, not "${input.type}"`,
|
|
1080
|
+
"INVALID_TITLE_FIELD",
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
if (collectionRow?.date_field === fieldSlug && input.type !== "datetime") {
|
|
1084
|
+
throw new SchemaError(
|
|
1085
|
+
`dateField "${fieldSlug}" must stay a datetime field, not "${input.type}"`,
|
|
1086
|
+
"INVALID_DATE_FIELD",
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
nextType = input.type;
|
|
1090
|
+
updates.type = input.type;
|
|
1091
|
+
updates.column_type = newColumnType;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (input.required !== undefined && input.required !== field.required) {
|
|
1095
|
+
throw new SchemaError(
|
|
1096
|
+
`Changing required for field "${fieldSlug}" requires a manual content migration.`,
|
|
1097
|
+
"FIELD_UPDATE_REQUIRES_MIGRATION",
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
if (input.unique !== undefined && input.unique !== field.unique) {
|
|
1101
|
+
throw new SchemaError(
|
|
1102
|
+
`Changing unique for field "${fieldSlug}" requires a manual content migration.`,
|
|
1103
|
+
"FIELD_UPDATE_REQUIRES_MIGRATION",
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
if (input.translatable === false && field.translatable) {
|
|
1107
|
+
throw new SchemaError(
|
|
1108
|
+
`Changing field "${fieldSlug}" to non-translatable requires a manual content migration.`,
|
|
1109
|
+
"FIELD_UPDATE_REQUIRES_MIGRATION",
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (input.label !== undefined) updates.label = input.label;
|
|
1114
|
+
if (input.required !== undefined) updates.required = input.required ? 1 : 0;
|
|
1115
|
+
if (input.unique !== undefined) updates.unique = input.unique ? 1 : 0;
|
|
1116
|
+
if (input.searchable !== undefined) updates.searchable = input.searchable ? 1 : 0;
|
|
1117
|
+
const indexedChanged = input.indexed !== undefined && input.indexed !== field.indexed;
|
|
1118
|
+
if (indexedChanged) updates.indexed = input.indexed ? 1 : 0;
|
|
1119
|
+
if (input.translatable !== undefined) {
|
|
1120
|
+
updates.translatable = input.translatable ? 1 : 0;
|
|
1121
|
+
}
|
|
1122
|
+
if (input.defaultValue !== undefined) {
|
|
1123
|
+
updates.default_value = JSON.stringify(input.defaultValue);
|
|
1124
|
+
}
|
|
1125
|
+
if (input.validation !== undefined) {
|
|
1126
|
+
updates.validation = input.validation ? JSON.stringify(input.validation) : null;
|
|
1127
|
+
}
|
|
1128
|
+
if (input.widget !== undefined) updates.widget = input.widget;
|
|
1129
|
+
if (input.options !== undefined) updates.options = JSON.stringify(input.options);
|
|
1130
|
+
if (input.sortOrder !== undefined) updates.sort_order = input.sortOrder;
|
|
1131
|
+
|
|
1132
|
+
assertIndexableField(nextType, input.indexed ?? field.indexed, fieldSlug);
|
|
1133
|
+
if (Object.keys(updates).length === 0) return field;
|
|
1134
|
+
|
|
1135
|
+
activeCoverageInvalidated = await invalidateContentMediaUsageSchemaChange(
|
|
1136
|
+
trx,
|
|
1137
|
+
collectionSlug,
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
if (Object.keys(updates).length > 0) {
|
|
1141
|
+
await trx.updateTable("_emdash_fields").set(updates).where("id", "=", field.id).execute();
|
|
1142
|
+
schemaMutated = true;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
if (indexedChanged) {
|
|
1146
|
+
if (input.indexed) {
|
|
1147
|
+
await this.createFieldIndex(collectionSlug, field.id, fieldSlug, trx);
|
|
1148
|
+
} else {
|
|
1149
|
+
await this.dropFieldIndex(field.id, trx);
|
|
1150
|
+
}
|
|
1151
|
+
schemaMutated = true;
|
|
1152
|
+
}
|
|
773
1153
|
|
|
774
1154
|
// Read the updated field via trx (not this.db) to avoid connection mutex deadlock
|
|
775
1155
|
const updatedRow = await trx
|
|
@@ -787,26 +1167,36 @@ export class SchemaRegistry {
|
|
|
787
1167
|
|
|
788
1168
|
// If searchable changed, sync FTS state for this collection
|
|
789
1169
|
const searchableChanged =
|
|
790
|
-
input.searchable !== undefined && input.searchable !== field.searchable;
|
|
1170
|
+
schemaMutated && input.searchable !== undefined && input.searchable !== field.searchable;
|
|
791
1171
|
if (searchableChanged) {
|
|
792
1172
|
await this.syncSearchState(collectionSlug, trx);
|
|
793
1173
|
}
|
|
794
1174
|
|
|
795
1175
|
return updated;
|
|
796
1176
|
});
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1177
|
+
if (schemaMutated) {
|
|
1178
|
+
if (activeCoverageInvalidated) {
|
|
1179
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1180
|
+
} else {
|
|
1181
|
+
await markContentMediaUsageCollectionStaleSafely(
|
|
1182
|
+
this.db,
|
|
1183
|
+
collectionSlug,
|
|
1184
|
+
"CONTENT_USAGE_STALE",
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
802
1188
|
return updatedField;
|
|
803
1189
|
} catch (error) {
|
|
804
1190
|
if (schemaMutated) {
|
|
805
|
-
|
|
806
|
-
this.db,
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1191
|
+
if (activeCoverageInvalidated) {
|
|
1192
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1193
|
+
} else {
|
|
1194
|
+
await markContentMediaUsageCollectionStaleSafely(
|
|
1195
|
+
this.db,
|
|
1196
|
+
collectionSlug,
|
|
1197
|
+
"CONTENT_USAGE_STALE",
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
810
1200
|
}
|
|
811
1201
|
throw error;
|
|
812
1202
|
}
|
|
@@ -866,6 +1256,17 @@ export class SchemaRegistry {
|
|
|
866
1256
|
"FIELD_NOT_FOUND",
|
|
867
1257
|
);
|
|
868
1258
|
}
|
|
1259
|
+
const activeCoverageInvalidated = await invalidateContentMediaUsageSchemaChange(
|
|
1260
|
+
this.db,
|
|
1261
|
+
collectionSlug,
|
|
1262
|
+
);
|
|
1263
|
+
|
|
1264
|
+
// If this field powers the collection's titleField/dateField,
|
|
1265
|
+
// clear that reference in the same transaction — otherwise the metadata
|
|
1266
|
+
// would point at a dropped column and later crash the content list sort.
|
|
1267
|
+
const collection = await this.getCollection(collectionSlug);
|
|
1268
|
+
const clearTitle = collection?.titleField === fieldSlug;
|
|
1269
|
+
const clearDate = collection?.dateField === fieldSlug;
|
|
869
1270
|
|
|
870
1271
|
let schemaMutated = false;
|
|
871
1272
|
try {
|
|
@@ -878,27 +1279,51 @@ export class SchemaRegistry {
|
|
|
878
1279
|
await trx.deleteFrom("_emdash_fields").where("id", "=", field.id).execute();
|
|
879
1280
|
schemaMutated = true;
|
|
880
1281
|
|
|
1282
|
+
if (clearTitle || clearDate) {
|
|
1283
|
+
await trx
|
|
1284
|
+
.updateTable("_emdash_collections")
|
|
1285
|
+
.set({
|
|
1286
|
+
...(clearTitle ? { title_field: null } : {}),
|
|
1287
|
+
...(clearDate ? { date_field: null } : {}),
|
|
1288
|
+
updated_at: new Date().toISOString(),
|
|
1289
|
+
})
|
|
1290
|
+
.where("slug", "=", collectionSlug)
|
|
1291
|
+
.execute();
|
|
1292
|
+
}
|
|
1293
|
+
|
|
881
1294
|
// If the deleted field was searchable, sync FTS state (removes old triggers)
|
|
882
1295
|
if (field.searchable) {
|
|
883
1296
|
await this.syncSearchState(collectionSlug, trx);
|
|
884
1297
|
}
|
|
885
1298
|
|
|
1299
|
+
if (field.indexed) {
|
|
1300
|
+
await this.dropFieldIndex(field.id, trx);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
886
1303
|
// Drop column from content table — safe now because FTS triggers are gone
|
|
887
1304
|
await this.dropColumn(collectionSlug, fieldSlug, trx);
|
|
888
1305
|
});
|
|
889
|
-
|
|
890
|
-
this.db,
|
|
891
|
-
|
|
892
|
-
"CONTENT_USAGE_STALE",
|
|
893
|
-
);
|
|
894
|
-
} catch (error) {
|
|
895
|
-
if (schemaMutated) {
|
|
1306
|
+
if (activeCoverageInvalidated) {
|
|
1307
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1308
|
+
} else {
|
|
896
1309
|
await markContentMediaUsageCollectionStaleSafely(
|
|
897
1310
|
this.db,
|
|
898
1311
|
collectionSlug,
|
|
899
1312
|
"CONTENT_USAGE_STALE",
|
|
900
1313
|
);
|
|
901
1314
|
}
|
|
1315
|
+
} catch (error) {
|
|
1316
|
+
if (schemaMutated) {
|
|
1317
|
+
if (activeCoverageInvalidated) {
|
|
1318
|
+
await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
1319
|
+
} else {
|
|
1320
|
+
await markContentMediaUsageCollectionStaleSafely(
|
|
1321
|
+
this.db,
|
|
1322
|
+
collectionSlug,
|
|
1323
|
+
"CONTENT_USAGE_STALE",
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
902
1327
|
throw error;
|
|
903
1328
|
}
|
|
904
1329
|
}
|
|
@@ -988,6 +1413,7 @@ export class SchemaRegistry {
|
|
|
988
1413
|
slug: string,
|
|
989
1414
|
db?: Kysely<Database>,
|
|
990
1415
|
fields: readonly CreateFieldInput[] = [],
|
|
1416
|
+
options: { ifNotExists?: boolean } = {},
|
|
991
1417
|
): Promise<void> {
|
|
992
1418
|
const conn = db ?? this.db;
|
|
993
1419
|
const tableName = this.getTableName(slug);
|
|
@@ -1009,6 +1435,7 @@ export class SchemaRegistry {
|
|
|
1009
1435
|
.addColumn("draft_revision_id", "text", (col) => col.references("revisions.id"))
|
|
1010
1436
|
.addColumn("locale", "text", (col) => col.notNull().defaultTo("en"))
|
|
1011
1437
|
.addColumn("translation_group", "text");
|
|
1438
|
+
if (options.ifNotExists) table = table.ifNotExists();
|
|
1012
1439
|
|
|
1013
1440
|
for (const field of fields) {
|
|
1014
1441
|
const columnName = this.getColumnName(field.slug);
|
|
@@ -1028,40 +1455,42 @@ export class SchemaRegistry {
|
|
|
1028
1455
|
.addUniqueConstraint(`${tableName}_slug_locale_unique`, ["slug", "locale"])
|
|
1029
1456
|
.execute();
|
|
1030
1457
|
|
|
1458
|
+
const createIndex = options.ifNotExists ? sql`CREATE INDEX IF NOT EXISTS` : sql`CREATE INDEX`;
|
|
1459
|
+
|
|
1031
1460
|
// Create standard indexes
|
|
1032
1461
|
await sql`
|
|
1033
|
-
|
|
1462
|
+
${createIndex} ${sql.ref(`idx_${tableName}_slug`)}
|
|
1034
1463
|
ON ${sql.ref(tableName)} (slug)
|
|
1035
1464
|
`.execute(conn);
|
|
1036
1465
|
|
|
1037
1466
|
await sql`
|
|
1038
|
-
|
|
1467
|
+
${createIndex} ${sql.ref(`idx_${tableName}_scheduled`)}
|
|
1039
1468
|
ON ${sql.ref(tableName)} (scheduled_at)
|
|
1040
1469
|
WHERE scheduled_at IS NOT NULL
|
|
1041
1470
|
`.execute(conn);
|
|
1042
1471
|
|
|
1043
1472
|
await sql`
|
|
1044
|
-
|
|
1473
|
+
${createIndex} ${sql.ref(`idx_${tableName}_live_revision`)}
|
|
1045
1474
|
ON ${sql.ref(tableName)} (live_revision_id)
|
|
1046
1475
|
`.execute(conn);
|
|
1047
1476
|
|
|
1048
1477
|
await sql`
|
|
1049
|
-
|
|
1478
|
+
${createIndex} ${sql.ref(`idx_${tableName}_draft_revision`)}
|
|
1050
1479
|
ON ${sql.ref(tableName)} (draft_revision_id)
|
|
1051
1480
|
`.execute(conn);
|
|
1052
1481
|
|
|
1053
1482
|
await sql`
|
|
1054
|
-
|
|
1483
|
+
${createIndex} ${sql.ref(`idx_${tableName}_author`)}
|
|
1055
1484
|
ON ${sql.ref(tableName)} (author_id)
|
|
1056
1485
|
`.execute(conn);
|
|
1057
1486
|
|
|
1058
1487
|
await sql`
|
|
1059
|
-
|
|
1488
|
+
${createIndex} ${sql.ref(`idx_${tableName}_primary_byline`)}
|
|
1060
1489
|
ON ${sql.ref(tableName)} (primary_byline_id)
|
|
1061
1490
|
`.execute(conn);
|
|
1062
1491
|
|
|
1063
1492
|
await sql`
|
|
1064
|
-
|
|
1493
|
+
${createIndex} ${sql.ref(`idx_${tableName}_locale`)}
|
|
1065
1494
|
ON ${sql.ref(tableName)} (locale)
|
|
1066
1495
|
`.execute(conn);
|
|
1067
1496
|
|
|
@@ -1070,33 +1499,33 @@ export class SchemaRegistry {
|
|
|
1070
1499
|
// (menu and reference resolution) need the first; reads that do need the
|
|
1071
1500
|
// second.
|
|
1072
1501
|
await sql`
|
|
1073
|
-
|
|
1502
|
+
${createIndex} ${sql.ref(`idx_${tableName}_tg_locale`)}
|
|
1074
1503
|
ON ${sql.ref(tableName)} (translation_group, locale)
|
|
1075
1504
|
`.execute(conn);
|
|
1076
1505
|
|
|
1077
1506
|
await sql`
|
|
1078
|
-
|
|
1507
|
+
${createIndex} ${sql.ref(`idx_${tableName}_del_tg_locale`)}
|
|
1079
1508
|
ON ${sql.ref(tableName)} (deleted_at, translation_group, locale)
|
|
1080
1509
|
`.execute(conn);
|
|
1081
1510
|
|
|
1082
1511
|
// Composite indexes for optimized query performance (see migration 033)
|
|
1083
1512
|
await sql`
|
|
1084
|
-
|
|
1513
|
+
${createIndex} ${sql.ref(`idx_${tableName}_deleted_updated_id`)}
|
|
1085
1514
|
ON ${sql.ref(tableName)} (deleted_at, updated_at DESC, id DESC)
|
|
1086
1515
|
`.execute(conn);
|
|
1087
1516
|
|
|
1088
1517
|
await sql`
|
|
1089
|
-
|
|
1518
|
+
${createIndex} ${sql.ref(`idx_${tableName}_deleted_status`)}
|
|
1090
1519
|
ON ${sql.ref(tableName)} (deleted_at, status)
|
|
1091
1520
|
`.execute(conn);
|
|
1092
1521
|
|
|
1093
1522
|
await sql`
|
|
1094
|
-
|
|
1523
|
+
${createIndex} ${sql.ref(`idx_${tableName}_deleted_created_id`)}
|
|
1095
1524
|
ON ${sql.ref(tableName)} (deleted_at, created_at DESC, id DESC)
|
|
1096
1525
|
`.execute(conn);
|
|
1097
1526
|
|
|
1098
1527
|
await sql`
|
|
1099
|
-
|
|
1528
|
+
${createIndex} ${sql.ref(`idx_${tableName}_deleted_published_id`)}
|
|
1100
1529
|
ON ${sql.ref(tableName)} (deleted_at, published_at DESC, id DESC)
|
|
1101
1530
|
`.execute(conn);
|
|
1102
1531
|
|
|
@@ -1105,16 +1534,67 @@ export class SchemaRegistry {
|
|
|
1105
1534
|
// inside Postgres's 63-byte identifier limit for long slugs; keep these
|
|
1106
1535
|
// names identical to migration 041.
|
|
1107
1536
|
await sql`
|
|
1108
|
-
|
|
1537
|
+
${createIndex} ${sql.ref(`idx_${tableName}_loc_upd`)}
|
|
1109
1538
|
ON ${sql.ref(tableName)} (deleted_at, locale, updated_at DESC, id DESC)
|
|
1110
1539
|
`.execute(conn);
|
|
1111
1540
|
|
|
1112
1541
|
await sql`
|
|
1113
|
-
|
|
1542
|
+
${createIndex} ${sql.ref(`idx_${tableName}_loc_crt`)}
|
|
1114
1543
|
ON ${sql.ref(tableName)} (deleted_at, locale, created_at DESC, id DESC)
|
|
1115
1544
|
`.execute(conn);
|
|
1116
1545
|
}
|
|
1117
1546
|
|
|
1547
|
+
private getFieldIndexName(fieldId: string): string {
|
|
1548
|
+
if (!FIELD_ID_PATTERN.test(fieldId)) {
|
|
1549
|
+
throw new SchemaError(`Invalid field id "${fieldId}"`, "INVALID_FIELD_ID");
|
|
1550
|
+
}
|
|
1551
|
+
return `idx_cf_${fieldId.toLowerCase()}`;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
private getLocaleFieldIndexName(fieldId: string): string {
|
|
1555
|
+
return `${this.getFieldIndexName(fieldId)}_loc`;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
private async createFieldIndex(
|
|
1559
|
+
collectionSlug: string,
|
|
1560
|
+
fieldId: string,
|
|
1561
|
+
fieldSlug: string,
|
|
1562
|
+
db?: Kysely<Database>,
|
|
1563
|
+
): Promise<void> {
|
|
1564
|
+
const conn = db ?? this.db;
|
|
1565
|
+
const tableName = this.getTableName(collectionSlug);
|
|
1566
|
+
const columnName = this.getColumnName(fieldSlug);
|
|
1567
|
+
const indexName = this.getFieldIndexName(fieldId);
|
|
1568
|
+
const localeIndexName = this.getLocaleFieldIndexName(fieldId);
|
|
1569
|
+
|
|
1570
|
+
await sql`
|
|
1571
|
+
CREATE INDEX IF NOT EXISTS ${sql.ref(indexName)}
|
|
1572
|
+
ON ${sql.ref(tableName)} (
|
|
1573
|
+
(${sql.ref(columnName)} IS NOT NULL),
|
|
1574
|
+
${sql.ref(columnName)},
|
|
1575
|
+
id
|
|
1576
|
+
)
|
|
1577
|
+
WHERE deleted_at IS NULL
|
|
1578
|
+
`.execute(conn);
|
|
1579
|
+
|
|
1580
|
+
await sql`
|
|
1581
|
+
CREATE INDEX IF NOT EXISTS ${sql.ref(localeIndexName)}
|
|
1582
|
+
ON ${sql.ref(tableName)} (
|
|
1583
|
+
locale,
|
|
1584
|
+
(${sql.ref(columnName)} IS NOT NULL),
|
|
1585
|
+
${sql.ref(columnName)},
|
|
1586
|
+
id
|
|
1587
|
+
)
|
|
1588
|
+
WHERE deleted_at IS NULL
|
|
1589
|
+
`.execute(conn);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
private async dropFieldIndex(fieldId: string, db?: Kysely<Database>): Promise<void> {
|
|
1593
|
+
const conn = db ?? this.db;
|
|
1594
|
+
await sql`DROP INDEX IF EXISTS ${sql.ref(this.getFieldIndexName(fieldId))}`.execute(conn);
|
|
1595
|
+
await sql`DROP INDEX IF EXISTS ${sql.ref(this.getLocaleFieldIndexName(fieldId))}`.execute(conn);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1118
1598
|
/**
|
|
1119
1599
|
* Add a column to a content table
|
|
1120
1600
|
*/
|
|
@@ -1314,10 +1794,16 @@ export class SchemaRegistry {
|
|
|
1314
1794
|
labelSingular: row.label_singular ?? undefined,
|
|
1315
1795
|
description: row.description ?? undefined,
|
|
1316
1796
|
icon: row.icon ?? undefined,
|
|
1797
|
+
admin: parseCollectionAdmin(row.admin_config),
|
|
1317
1798
|
supports: parseSupports(row.supports),
|
|
1318
1799
|
source: row.source && isCollectionSource(row.source) ? row.source : undefined,
|
|
1319
1800
|
hasSeo: row.has_seo === 1,
|
|
1801
|
+
// Raw value; undefined when unset. The admin list resolves the
|
|
1802
|
+
// default (title fallback chain / updatedAt) at the point of use.
|
|
1803
|
+
titleField: row.title_field ?? undefined,
|
|
1804
|
+
dateField: row.date_field ?? undefined,
|
|
1320
1805
|
urlPattern: row.url_pattern ?? undefined,
|
|
1806
|
+
routable: row.routable !== 0,
|
|
1321
1807
|
hidden: row.hidden === 1,
|
|
1322
1808
|
sortOrder: row.sort_order ?? undefined,
|
|
1323
1809
|
commentsEnabled: row.comments_enabled === 1,
|
|
@@ -1351,6 +1837,7 @@ export class SchemaRegistry {
|
|
|
1351
1837
|
options: row.options ? JSON.parse(row.options) : undefined,
|
|
1352
1838
|
sortOrder: row.sort_order,
|
|
1353
1839
|
searchable: row.searchable === 1,
|
|
1840
|
+
indexed: row.indexed === 1,
|
|
1354
1841
|
translatable: row.translatable !== 0,
|
|
1355
1842
|
createdAt: row.created_at,
|
|
1356
1843
|
};
|
|
@@ -1430,6 +1917,9 @@ export class SchemaRegistry {
|
|
|
1430
1917
|
): Promise<Collection> {
|
|
1431
1918
|
// Verify table exists
|
|
1432
1919
|
const tableName = this.getTableName(slug);
|
|
1920
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, slug)) {
|
|
1921
|
+
throw new SchemaError(`Collection "${slug}" is already registered`, "COLLECTION_EXISTS");
|
|
1922
|
+
}
|
|
1433
1923
|
const exists = await tableExists(this.db, tableName);
|
|
1434
1924
|
|
|
1435
1925
|
if (!exists) {
|
|
@@ -1438,32 +1928,64 @@ export class SchemaRegistry {
|
|
|
1438
1928
|
|
|
1439
1929
|
// Check if already registered
|
|
1440
1930
|
const existing = await this.getCollection(slug);
|
|
1441
|
-
if (
|
|
1931
|
+
if (await isMediaUsageCollectionSlugDeleting(this.db, slug)) {
|
|
1932
|
+
throw new SchemaError(`Collection "${slug}" is already registered`, "COLLECTION_EXISTS");
|
|
1933
|
+
}
|
|
1934
|
+
if (
|
|
1935
|
+
existing &&
|
|
1936
|
+
!(await canResumeMediaUsageCollectionCapture(this.db, {
|
|
1937
|
+
collectionId: existing.id,
|
|
1938
|
+
collectionSlug: existing.slug,
|
|
1939
|
+
}))
|
|
1940
|
+
) {
|
|
1442
1941
|
throw new SchemaError(`Collection "${slug}" is already registered`, "COLLECTION_EXISTS");
|
|
1443
1942
|
}
|
|
1444
1943
|
|
|
1445
1944
|
// Create collection entry
|
|
1446
|
-
const
|
|
1945
|
+
const proposedId = existing?.id ?? ulid();
|
|
1447
1946
|
const label = options?.label || this.slugToLabel(slug);
|
|
1448
1947
|
|
|
1449
1948
|
let collectionRegistered = false;
|
|
1450
1949
|
try {
|
|
1451
|
-
await this.db
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
|
|
1950
|
+
const capture = await prepareMediaUsageCollectionCapture(this.db, {
|
|
1951
|
+
collectionId: proposedId,
|
|
1952
|
+
collectionSlug: slug,
|
|
1953
|
+
registeredCollectionId: existing?.id,
|
|
1954
|
+
});
|
|
1955
|
+
if (capture.captureRequired) {
|
|
1956
|
+
await installPreparedMediaUsageCollectionCapture(this.db, {
|
|
1957
|
+
collectionId: capture.collectionId,
|
|
1958
|
+
collectionSlug: slug,
|
|
1959
|
+
});
|
|
1960
|
+
await markMediaUsageCollectionCaptureReady(this.db, {
|
|
1961
|
+
collectionId: capture.collectionId,
|
|
1962
|
+
collectionSlug: slug,
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
if (!capture.registrationExists) {
|
|
1966
|
+
await this.db
|
|
1967
|
+
.insertInto("_emdash_collections")
|
|
1968
|
+
.values({
|
|
1969
|
+
id: capture.collectionId,
|
|
1970
|
+
slug,
|
|
1971
|
+
label,
|
|
1972
|
+
label_singular: options?.labelSingular ?? null,
|
|
1973
|
+
description: options?.description ?? null,
|
|
1974
|
+
icon: null,
|
|
1975
|
+
supports: JSON.stringify([]),
|
|
1976
|
+
source: "discovered",
|
|
1977
|
+
has_seo: 0,
|
|
1978
|
+
url_pattern: null,
|
|
1979
|
+
})
|
|
1980
|
+
.execute();
|
|
1981
|
+
collectionRegistered = true;
|
|
1982
|
+
}
|
|
1983
|
+
if (capture.captureRequired) {
|
|
1984
|
+
await finalizeMediaUsageCollectionCapture(this.db, {
|
|
1985
|
+
collectionId: capture.collectionId,
|
|
1986
|
+
collectionSlug: slug,
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1467
1989
|
|
|
1468
1990
|
const collection = await this.getCollection(slug);
|
|
1469
1991
|
if (!collection) {
|