emdash 0.31.0 → 0.32.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/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +16 -14
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +4 -4
- package/dist/{api-EibxGP-V.mjs → api-DgPbMlng.mjs} +24 -20
- package/dist/api-DgPbMlng.mjs.map +1 -0
- package/dist/{api-tokens-uPt8UDpx.mjs → api-tokens-p-iMzvXR.mjs} +2 -2
- package/dist/{api-tokens-uPt8UDpx.mjs.map → api-tokens-p-iMzvXR.mjs.map} +1 -1
- package/dist/{apply-fGHCAwWN.mjs → apply-1_6ra7NP.mjs} +19 -19
- package/dist/{apply-fGHCAwWN.mjs.map → apply-1_6ra7NP.mjs.map} +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.mjs +5 -1
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +1 -1
- package/dist/astro/middleware.d.mts +10 -10
- package/dist/astro/middleware.mjs +94 -61
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +15 -14
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +15 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +15 -15
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +9 -9
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +9 -9
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +12 -10
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +37 -35
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +37 -35
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +36 -34
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +36 -34
- 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 +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +36 -34
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +7 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +7 -7
- package/dist/astro/routes/api/auth/logout.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/me.mjs +7 -7
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +8 -8
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +7 -7
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +7 -7
- package/dist/astro/routes/api/auth/passkey/verify.mjs +7 -7
- package/dist/astro/routes/api/auth/signup/complete.mjs +7 -7
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +16 -14
- 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 +16 -14
- 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 +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +14 -13
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -11
- 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 +7 -7
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +11 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +20 -19
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +41 -41
- package/dist/astro/routes/api/media/_id_/confirm.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +105 -36
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/upload.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/upload.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs +168 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/usage.mjs +14 -12
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +21 -14
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
- package/dist/astro/routes/api/media/providers/index.mjs +3 -3
- package/dist/astro/routes/api/media/upload-url.d.mts.map +1 -1
- package/dist/astro/routes/api/media/upload-url.mjs +34 -23
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +13 -12
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -8
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +9 -8
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -8
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -8
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +9 -8
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +9 -8
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +30 -8
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +5 -5
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
- package/dist/astro/routes/api/redirects/index.mjs +11 -11
- package/dist/astro/routes/api/relations/_id_/index.mjs +16 -14
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +12 -10
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +16 -14
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +36 -34
- 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 +36 -34
- 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 +36 -34
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +36 -34
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +36 -34
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +10 -8
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +36 -34
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +36 -34
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +12 -11
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +11 -10
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +12 -11
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +8 -7
- package/dist/astro/routes/api/search/stats.mjs.map +1 -1
- package/dist/astro/routes/api/search/suggest.mjs +11 -10
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +10 -10
- package/dist/astro/routes/api/sections/index.mjs +10 -10
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/export.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/index.mjs +5 -5
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +12 -12
- package/dist/astro/routes/api/setup/admin-verify.mjs +8 -8
- package/dist/astro/routes/api/setup/admin.mjs +8 -8
- package/dist/astro/routes/api/setup/dev-bypass.mjs +24 -22
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +24 -22
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +5 -5
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +14 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +14 -13
- 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 +19 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +14 -13
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +4 -4
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/index.mjs +10 -10
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +7 -7
- package/dist/astro/routes/sitemap.xml.mjs +5 -5
- package/dist/astro/types.d.mts +14 -13
- 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-6WPZa1xZ.mjs → authorize-R5iYYrpa.mjs} +2 -2
- package/dist/{authorize-6WPZa1xZ.mjs.map → authorize-R5iYYrpa.mjs.map} +1 -1
- package/dist/{backup-Qr9PaGUo.mjs → backup-LpQ1V_sR.mjs} +2 -2
- package/dist/{backup-Qr9PaGUo.mjs.map → backup-LpQ1V_sR.mjs.map} +1 -1
- package/dist/{byline-BTOxUlFF.mjs → byline-C5TAqs8N.mjs} +6 -6
- package/dist/{byline-BTOxUlFF.mjs.map → byline-C5TAqs8N.mjs.map} +1 -1
- package/dist/{byline-fields-CdU_LTF1.mjs → byline-fields-T9ZLZMxJ.mjs} +1 -1
- package/dist/{byline-fields-CdU_LTF1.mjs.map → byline-fields-T9ZLZMxJ.mjs.map} +1 -1
- package/dist/{bylines-FyZu6TbJ.mjs → bylines-B8-WGdja.mjs} +6 -6
- package/dist/{bylines-FyZu6TbJ.mjs.map → bylines-B8-WGdja.mjs.map} +1 -1
- package/dist/{bylines-oVN0iPwX.mjs → bylines-DGuqBLjV.mjs} +5 -5
- package/dist/{bylines-oVN0iPwX.mjs.map → bylines-DGuqBLjV.mjs.map} +1 -1
- package/dist/{cache-DDwy3JDW.mjs → cache-B26cufFd.mjs} +2 -2
- package/dist/{cache-DDwy3JDW.mjs.map → cache-B26cufFd.mjs.map} +1 -1
- package/dist/{chunks-Bq-5DPrD.mjs → chunks-D5dlPeRb.mjs} +2 -2
- package/dist/{chunks-Bq-5DPrD.mjs.map → chunks-D5dlPeRb.mjs.map} +1 -1
- package/dist/cli/index.mjs +20 -19
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +2 -2
- package/dist/{comment-B9cUud8H.mjs → comment-DnTxxVHv.mjs} +2 -2
- package/dist/{comment-B9cUud8H.mjs.map → comment-DnTxxVHv.mjs.map} +1 -1
- package/dist/{comment-reaction-VUXO981F.mjs → comment-reaction-BUlUz2bh.mjs} +2 -2
- package/dist/{comment-reaction-VUXO981F.mjs.map → comment-reaction-BUlUz2bh.mjs.map} +1 -1
- package/dist/{comments-PXj1E9Si.mjs → comments-QPKgK3nk.mjs} +3 -3
- package/dist/{comments-PXj1E9Si.mjs.map → comments-QPKgK3nk.mjs.map} +1 -1
- package/dist/{config-B6b_BobR.mjs → config-DyF3OKg_.mjs} +15 -10
- package/dist/config-DyF3OKg_.mjs.map +1 -0
- package/dist/{content-BC43pICM.mjs → content-CpfKV9QE.mjs} +9 -9
- package/dist/content-CpfKV9QE.mjs.map +1 -0
- package/dist/{content-refresh-CPMSauD3.mjs → content-refresh-DgqUBeTv.mjs} +5 -5
- package/dist/{content-refresh-CPMSauD3.mjs.map → content-refresh-DgqUBeTv.mjs.map} +1 -1
- package/dist/{context-DOurRIrb.mjs → context-kO4YZB03.mjs} +10 -10
- package/dist/{context-DOurRIrb.mjs.map → context-kO4YZB03.mjs.map} +1 -1
- package/dist/{dashboard-CBm4zhc3.mjs → dashboard-DoBwPnON.mjs} +4 -4
- package/dist/{dashboard-CBm4zhc3.mjs.map → dashboard-DoBwPnON.mjs.map} +1 -1
- package/dist/db/index.d.mts +2 -2
- package/dist/db/index.mjs +3 -2
- package/dist/db/index.mjs.map +1 -1
- package/dist/{device-flow-BeA6lUS1.mjs → device-flow-DhUsyJU6.mjs} +4 -4
- package/dist/{device-flow-BeA6lUS1.mjs.map → device-flow-DhUsyJU6.mjs.map} +1 -1
- package/dist/{dialect-helpers-BtOwo2us.mjs → dialect-helpers-DFwyWjTM.mjs} +21 -2
- package/dist/dialect-helpers-DFwyWjTM.mjs.map +1 -0
- package/dist/{error-DJ98TRbQ.mjs → error-DmmN74gW.mjs} +2 -2
- package/dist/{error-DJ98TRbQ.mjs.map → error-DmmN74gW.mjs.map} +1 -1
- package/dist/{escape-CFedIB1C.mjs → escape-CdW31WsG.mjs} +1 -1
- package/dist/{escape-CFedIB1C.mjs.map → escape-CdW31WsG.mjs.map} +1 -1
- package/dist/{field-defs-cache-KfNJ_qLQ.mjs → field-defs-cache-QMVnzTH6.mjs} +2 -2
- package/dist/{field-defs-cache-KfNJ_qLQ.mjs.map → field-defs-cache-QMVnzTH6.mjs.map} +1 -1
- package/dist/{fts-manager-hyCU9OOp.mjs → fts-manager-vncsZIJm.mjs} +3 -3
- package/dist/{fts-manager-hyCU9OOp.mjs.map → fts-manager-vncsZIJm.mjs.map} +1 -1
- package/dist/{hash-DFFrkivP.mjs → hash-Cb7U1b5M.mjs} +8 -4
- package/dist/hash-Cb7U1b5M.mjs.map +1 -0
- package/dist/{hreflang-CbYeCzl9.mjs → hreflang-Bg-zMpkr.mjs} +7 -7
- package/dist/{hreflang-CbYeCzl9.mjs.map → hreflang-Bg-zMpkr.mjs.map} +1 -1
- package/dist/{hreflang-CIxH_LKz.d.mts → hreflang-CZbSx6Bg.d.mts} +2 -2
- package/dist/{hreflang-CIxH_LKz.d.mts.map → hreflang-CZbSx6Bg.d.mts.map} +1 -1
- package/dist/{import-oDYCgNYQ.mjs → import-PKhLeXvn.mjs} +2 -2
- package/dist/{import-oDYCgNYQ.mjs.map → import-PKhLeXvn.mjs.map} +1 -1
- package/dist/{index-BEui-cRd.d.mts → index-BeNto_Vs.d.mts} +3 -3
- package/dist/{index-BEui-cRd.d.mts.map → index-BeNto_Vs.d.mts.map} +1 -1
- package/dist/{index-BcEH_FfS.d.mts → index-j9rTh3cp.d.mts} +68 -18
- package/dist/index-j9rTh3cp.d.mts.map +1 -0
- package/dist/index.d.mts +18 -18
- package/dist/index.mjs +49 -49
- package/dist/{load-Dg5gtWma.mjs → load-BwTdWE8B.mjs} +2 -2
- package/dist/{load-Dg5gtWma.mjs.map → load-BwTdWE8B.mjs.map} +1 -1
- package/dist/{loader-D4rigvjR.mjs → loader-C1XOLV5b.mjs} +4 -4
- package/dist/{loader-D4rigvjR.mjs.map → loader-C1XOLV5b.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-BJ6SRY3g.mjs → media-DWIzoVFL.mjs} +8 -4
- package/dist/{media-BJ6SRY3g.mjs.map → media-DWIzoVFL.mjs.map} +1 -1
- package/dist/{media-allowlist-jUppPWFy.mjs → media-allowlist-B7TPD6aq.mjs} +1 -1
- package/dist/{media-allowlist-jUppPWFy.mjs.map → media-allowlist-B7TPD6aq.mjs.map} +1 -1
- package/dist/{media-its1WLYv.mjs → media-tQDZEdu7.mjs} +60 -15
- package/dist/media-tQDZEdu7.mjs.map +1 -0
- package/dist/{media-upload-DNu3QySc.mjs → media-upload-Bc9Nc5Zf.mjs} +6 -6
- package/dist/{media-upload-DNu3QySc.mjs.map → media-upload-Bc9Nc5Zf.mjs.map} +1 -1
- package/dist/{media-usage-DPQ3K4xB.mjs → media-usage-DPJcNaAq.mjs} +6 -6
- package/dist/{media-usage-DPQ3K4xB.mjs.map → media-usage-DPJcNaAq.mjs.map} +1 -1
- package/dist/{menus-BMGzWyWH.mjs → menus-BxPLFfIc.mjs} +3 -3
- package/dist/{menus-BMGzWyWH.mjs.map → menus-BxPLFfIc.mjs.map} +1 -1
- package/dist/{menus-CPf_SW7u.mjs → menus-C6qhqP4X.mjs} +8 -8
- package/dist/{menus-CPf_SW7u.mjs.map → menus-C6qhqP4X.mjs.map} +1 -1
- package/dist/{oauth-authorization-oqfbBuMH.mjs → oauth-authorization-C9tFinly.mjs} +4 -4
- package/dist/{oauth-authorization-oqfbBuMH.mjs.map → oauth-authorization-C9tFinly.mjs.map} +1 -1
- package/dist/{oauth-clients-BlrUHAsf.mjs → oauth-clients-BwTxE1aE.mjs} +1 -1
- package/dist/{oauth-clients-BlrUHAsf.mjs.map → oauth-clients-BwTxE1aE.mjs.map} +1 -1
- package/dist/{oauth-state-store-DnvjRMy6.mjs → oauth-state-store-DaRUwPWO.mjs} +1 -1
- package/dist/{oauth-state-store-DnvjRMy6.mjs.map → oauth-state-store-DaRUwPWO.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-oUllxvAv.mjs → oauth-user-lookup-CzuzOSlF.mjs} +1 -1
- package/dist/{oauth-user-lookup-oUllxvAv.mjs.map → oauth-user-lookup-CzuzOSlF.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-BqMkWfYa.d.mts → options-aeIs8WFu.d.mts} +3 -3
- package/dist/{options-BqMkWfYa.d.mts.map → options-aeIs8WFu.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-53zyxlpv.mjs → parse-BL49yb9D.mjs} +2 -2
- package/dist/{parse-53zyxlpv.mjs.map → parse-BL49yb9D.mjs.map} +1 -1
- package/dist/{passkey-config-C-SKpc0-.mjs → passkey-config-KMhgFjdQ.mjs} +1 -1
- package/dist/{passkey-config-C-SKpc0-.mjs.map → passkey-config-KMhgFjdQ.mjs.map} +1 -1
- package/dist/{placeholder-Dop47JMM.d.mts → placeholder-Dxo5Zt58.d.mts} +1 -1
- package/dist/{placeholder-Dop47JMM.d.mts.map → placeholder-Dxo5Zt58.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/{portable-text-sDj92Kxv.mjs → portable-text-CNahFfj6.mjs} +1 -1
- package/dist/{portable-text-sDj92Kxv.mjs.map → portable-text-CNahFfj6.mjs.map} +1 -1
- package/dist/{query-DdFGHzQF.mjs → query-1xOcEy18.mjs} +3 -3
- package/dist/{query-DdFGHzQF.mjs.map → query-1xOcEy18.mjs.map} +1 -1
- package/dist/{query-BbJQ-dGg.mjs → query-DCiXI7OZ.mjs} +36 -16
- package/dist/query-DCiXI7OZ.mjs.map +1 -0
- package/dist/{rate-limit-D3IEiUi2.mjs → rate-limit-Vkp9gQ1Y.mjs} +2 -2
- package/dist/{rate-limit-D3IEiUi2.mjs.map → rate-limit-Vkp9gQ1Y.mjs.map} +1 -1
- package/dist/{redirect-BoUac4NT.mjs → redirect-BJ6d1yHh.mjs} +3 -3
- package/dist/{redirect-BoUac4NT.mjs.map → redirect-BJ6d1yHh.mjs.map} +1 -1
- package/dist/{redirect-Botom7X6.mjs → redirect-CDgfv9vh.mjs} +1 -1
- package/dist/{redirect-Botom7X6.mjs.map → redirect-CDgfv9vh.mjs.map} +1 -1
- package/dist/{redirects-D457qwt0.mjs → redirects-BOn2DIUs.mjs} +8 -4
- package/dist/redirects-BOn2DIUs.mjs.map +1 -0
- package/dist/{redirects-ChbpqKiS.mjs → redirects-Cwkq2H-G.mjs} +3 -3
- package/dist/{redirects-ChbpqKiS.mjs.map → redirects-Cwkq2H-G.mjs.map} +1 -1
- package/dist/{registry-y21kjhfG.mjs → registry-BP1JK2xh.mjs} +6 -6
- package/dist/{registry-y21kjhfG.mjs.map → registry-BP1JK2xh.mjs.map} +1 -1
- package/dist/{relation-Du0r04E0.mjs → relation-DJ5DZh7B.mjs} +3 -3
- package/dist/{relation-Du0r04E0.mjs.map → relation-DJ5DZh7B.mjs.map} +1 -1
- package/dist/{relations-CZMpBqEd.mjs → relations-C4duJnwI.mjs} +2 -2
- package/dist/{relations-CZMpBqEd.mjs.map → relations-C4duJnwI.mjs.map} +1 -1
- package/dist/{relations-BKybBoOX.d.mts → relations-DHFQGX0h.d.mts} +19 -8
- package/dist/relations-DHFQGX0h.d.mts.map +1 -0
- package/dist/{relations-DtX1UMBH.mjs → relations-DpTjftCl.mjs} +6 -6
- package/dist/{relations-DtX1UMBH.mjs.map → relations-DpTjftCl.mjs.map} +1 -1
- package/dist/{resolve-DFr4kq72.mjs → resolve-BUvFE0Lr.mjs} +2 -2
- package/dist/{resolve-DFr4kq72.mjs.map → resolve-BUvFE0Lr.mjs.map} +1 -1
- package/dist/{runner-BdeLEgad.mjs → runner-BsI18UgP.mjs} +230 -212
- package/dist/runner-BsI18UgP.mjs.map +1 -0
- package/dist/{runner-Dd8m8k9F.d.mts → runner-CHdkERbt.d.mts} +2 -2
- package/dist/{runner-Dd8m8k9F.d.mts.map → runner-CHdkERbt.d.mts.map} +1 -1
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +3 -3
- package/dist/{schema-BH8P8vaC.mjs → schema-eqZhkR0S.mjs} +3 -3
- package/dist/{schema-BH8P8vaC.mjs.map → schema-eqZhkR0S.mjs.map} +1 -1
- package/dist/{scopes-DTIkIaGA.mjs → scopes-Be2d8bSb.mjs} +3 -3
- package/dist/{scopes-DTIkIaGA.mjs.map → scopes-Be2d8bSb.mjs.map} +1 -1
- package/dist/{search-D-Yhpmvs.mjs → search-CeO678cp.mjs} +6 -6
- package/dist/{search-D-Yhpmvs.mjs.map → search-CeO678cp.mjs.map} +1 -1
- package/dist/{secrets-CQ-69kF9.mjs → secrets-870d-7yA.mjs} +1 -1
- package/dist/{secrets-CQ-69kF9.mjs.map → secrets-870d-7yA.mjs.map} +1 -1
- package/dist/{sections-CzVBAKjw.mjs → sections-DSuEfirn.mjs} +3 -3
- package/dist/{sections-CzVBAKjw.mjs.map → sections-DSuEfirn.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +18 -16
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +14 -12
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-kJzVAmmu.mjs → seo-BAPKiED8.mjs} +2 -2
- package/dist/{seo-kJzVAmmu.mjs.map → seo-BAPKiED8.mjs.map} +1 -1
- package/dist/{service-CQnc276a.mjs → service-DyFT-k-R.mjs} +3 -3
- package/dist/{service-CQnc276a.mjs.map → service-DyFT-k-R.mjs.map} +1 -1
- package/dist/{session-user-DbHqKDKe.mjs → session-user-BrK2zz7S.mjs} +1 -1
- package/dist/{session-user-DbHqKDKe.mjs.map → session-user-BrK2zz7S.mjs.map} +1 -1
- package/dist/{settings-Dtc0DU31.mjs → settings-CREKyj8I.mjs} +3 -3
- package/dist/{settings-Dtc0DU31.mjs.map → settings-CREKyj8I.mjs.map} +1 -1
- package/dist/{settings-C2PaBS49.mjs → settings-DgKouY2S.mjs} +3 -3
- package/dist/{settings-C2PaBS49.mjs.map → settings-DgKouY2S.mjs.map} +1 -1
- package/dist/{setup-complete-CdIlqloh.mjs → setup-complete-L7bMK2VI.mjs} +1 -1
- package/dist/{setup-complete-CdIlqloh.mjs.map → setup-complete-L7bMK2VI.mjs.map} +1 -1
- package/dist/{setup-nonce-DqiIPr-J.mjs → setup-nonce-Ct5tjWcq.mjs} +1 -1
- package/dist/{setup-nonce-DqiIPr-J.mjs.map → setup-nonce-Ct5tjWcq.mjs.map} +1 -1
- package/dist/{site-url-NGJT6NTU.mjs → site-url-8N3kSyVZ.mjs} +1 -1
- package/dist/{site-url-NGJT6NTU.mjs.map → site-url-8N3kSyVZ.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{taxonomies-HI9fnTdp.mjs → taxonomies-B61CRSha.mjs} +94 -39
- package/dist/taxonomies-B61CRSha.mjs.map +1 -0
- package/dist/{taxonomies-rMeBzOjX.mjs → taxonomies-Dbdki3Un.mjs} +9 -8
- package/dist/taxonomies-Dbdki3Un.mjs.map +1 -0
- package/dist/{taxonomy-0mCI25HN.mjs → taxonomy-DvwWAPvA.mjs} +3 -3
- package/dist/{taxonomy-0mCI25HN.mjs.map → taxonomy-DvwWAPvA.mjs.map} +1 -1
- package/dist/{transport-CKrlqSpD.mjs → transport-BWQo0Foy.mjs} +1 -1
- package/dist/{transport-CKrlqSpD.mjs.map → transport-BWQo0Foy.mjs.map} +1 -1
- package/dist/{transport-Vd7VdqHv.d.mts → transport-DokJOScS.d.mts} +1 -1
- package/dist/{transport-Vd7VdqHv.d.mts.map → transport-DokJOScS.d.mts.map} +1 -1
- package/dist/{types-DPKhI5ib.d.mts → types-84Bque3-.d.mts} +9 -1
- package/dist/types-84Bque3-.d.mts.map +1 -0
- package/dist/{types-BvB7gDOD.d.mts → types-BQY7VYw6.d.mts} +2 -2
- package/dist/{types-BvB7gDOD.d.mts.map → types-BQY7VYw6.d.mts.map} +1 -1
- package/dist/{types-B4vm81VH.d.mts → types-C9P3ysxq.d.mts} +1 -1
- package/dist/{types-B4vm81VH.d.mts.map → types-C9P3ysxq.d.mts.map} +1 -1
- package/dist/{types-B97jg3aW.d.mts → types-CcSZCcF1.d.mts} +1 -1
- package/dist/{types-B97jg3aW.d.mts.map → types-CcSZCcF1.d.mts.map} +1 -1
- package/dist/{types-BNfPHfay.d.mts → types-DQLZ58GV.d.mts} +1 -1
- package/dist/{types-BNfPHfay.d.mts.map → types-DQLZ58GV.d.mts.map} +1 -1
- package/dist/{types-BfYUPJdP.d.mts → types-DqZVPILm.d.mts} +2 -2
- package/dist/{types-BfYUPJdP.d.mts.map → types-DqZVPILm.d.mts.map} +1 -1
- package/dist/{types-C7U0HlEr.d.mts → types-Dr2GLlwu.d.mts} +1 -1
- package/dist/{types-C7U0HlEr.d.mts.map → types-Dr2GLlwu.d.mts.map} +1 -1
- package/dist/{types-iVeZ5g6N.d.mts → types-DsAMyD_o.d.mts} +1 -1
- package/dist/{types-iVeZ5g6N.d.mts.map → types-DsAMyD_o.d.mts.map} +1 -1
- package/dist/{types-CrRUFdej.mjs → types-XrQQ-Aex.mjs} +2 -2
- package/dist/{types-CrRUFdej.mjs.map → types-XrQQ-Aex.mjs.map} +1 -1
- package/dist/{types-Kmaxdarz.d.mts → types-jISEalTX.d.mts} +1 -1
- package/dist/{types-Kmaxdarz.d.mts.map → types-jISEalTX.d.mts.map} +1 -1
- package/dist/upload-attempts-C5yd6Gae.mjs +27 -0
- package/dist/upload-attempts-C5yd6Gae.mjs.map +1 -0
- package/dist/{user-aTXqmXBz.mjs → user-BAumEmpA.mjs} +3 -3
- package/dist/{user-aTXqmXBz.mjs.map → user-BAumEmpA.mjs.map} +1 -1
- package/dist/{validate-CDT1jl6_.mjs → validate-Bs_wT2ul.mjs} +3 -3
- package/dist/{validate-CDT1jl6_.mjs.map → validate-Bs_wT2ul.mjs.map} +1 -1
- package/dist/{validate-DULfgpJP.d.mts → validate-CdYcY-Ln.d.mts} +5 -5
- package/dist/{validate-DULfgpJP.d.mts.map → validate-CdYcY-Ln.d.mts.map} +1 -1
- package/dist/{validation-DlD0E35W.mjs → validation-BngR0nit.mjs} +10 -8
- package/dist/{validation-DlD0E35W.mjs.map → validation-BngR0nit.mjs.map} +1 -1
- package/dist/version-Bdfb34kk.mjs +7 -0
- package/dist/{version-Ci6bw6YK.mjs.map → version-Bdfb34kk.mjs.map} +1 -1
- package/dist/{widgets-5fipNkMT.mjs → widgets-L-VndTKD.mjs} +2 -2
- package/dist/{widgets-5fipNkMT.mjs.map → widgets-L-VndTKD.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-BmUnBNgz.mjs → wxr-taxonomies-BexjtNid.mjs} +4 -4
- package/dist/{wxr-taxonomies-BmUnBNgz.mjs.map → wxr-taxonomies-BexjtNid.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-B4tMuN5T.d.mts → wxr-taxonomies-DueaLFd9.d.mts} +1 -1
- package/dist/{wxr-taxonomies-B4tMuN5T.d.mts.map → wxr-taxonomies-DueaLFd9.d.mts.map} +1 -1
- package/dist/{zod-generator-CwkHWz4f.mjs → zod-generator-DMzfga3g.mjs} +3 -3
- package/dist/{zod-generator-CwkHWz4f.mjs.map → zod-generator-DMzfga3g.mjs.map} +1 -1
- package/package.json +8 -7
- package/src/api/handlers/media.ts +4 -4
- package/src/api/handlers/taxonomies.ts +10 -9
- package/src/api/openapi/document.ts +36 -3
- package/src/api/schemas/media.ts +9 -2
- package/src/api/schemas/taxonomies.ts +16 -1
- package/src/astro/integration/routes.ts +5 -0
- package/src/astro/prefetch.ts +7 -2
- package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
- package/src/astro/routes/api/media/[id]/confirm.ts +148 -59
- package/src/astro/routes/api/media/[id]/upload.ts +262 -0
- package/src/astro/routes/api/media/[id].ts +19 -10
- package/src/astro/routes/api/media/upload-url.ts +28 -31
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +6 -3
- package/src/astro/types.ts +1 -0
- package/src/cleanup.ts +24 -1
- package/src/components/InlinePortableTextEditor.tsx +4 -0
- package/src/components/code-mark.ts +11 -0
- package/src/components/widgets/Categories.astro +1 -1
- package/src/components/widgets/Tags.astro +1 -1
- package/src/database/dialect-helpers.ts +38 -0
- package/src/database/migrations/054_media_upload_attempts.ts +41 -0
- package/src/database/migrations/runner.ts +2 -0
- package/src/database/repositories/content.ts +2 -5
- package/src/database/repositories/media.ts +158 -28
- package/src/database/types.ts +10 -0
- package/src/emdash-runtime.ts +13 -0
- package/src/i18n/config.ts +17 -10
- package/src/index.ts +1 -0
- package/src/media/upload-attempts.ts +33 -0
- package/src/query.ts +29 -2
- package/src/storage/s3.ts +1 -1
- package/src/taxonomies/index.ts +64 -23
- package/src/taxonomies/term-counts.ts +54 -24
- package/src/utils/hash.ts +14 -3
- package/dist/api-EibxGP-V.mjs.map +0 -1
- package/dist/config-B6b_BobR.mjs.map +0 -1
- package/dist/content-BC43pICM.mjs.map +0 -1
- package/dist/dialect-helpers-BtOwo2us.mjs.map +0 -1
- package/dist/hash-DFFrkivP.mjs.map +0 -1
- package/dist/index-BcEH_FfS.d.mts.map +0 -1
- package/dist/media-its1WLYv.mjs.map +0 -1
- package/dist/query-BbJQ-dGg.mjs.map +0 -1
- package/dist/redirects-D457qwt0.mjs.map +0 -1
- package/dist/relations-BKybBoOX.d.mts.map +0 -1
- package/dist/runner-BdeLEgad.mjs.map +0 -1
- package/dist/taxonomies-HI9fnTdp.mjs.map +0 -1
- package/dist/taxonomies-rMeBzOjX.mjs.map +0 -1
- package/dist/types-DPKhI5ib.d.mts.map +0 -1
- package/dist/version-Ci6bw6YK.mjs +0 -7
- /package/dist/{api-tokens-Cvmixds7.mjs → api-tokens-CEsW_jCg.mjs} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/import/wordpress-plugin/execute.ts"],"sourcesContent":["/**\n * WordPress Plugin execute import endpoint\n *\n * POST /_emdash/api/import/wordpress-plugin/execute\n *\n * Imports content from WordPress via EmDash Exporter plugin API.\n */\n\nimport type { APIRoute } from \"astro\";\nimport {\n\tContentRepository,\n\tSchemaRegistry,\n\ttype WxrCategory,\n\ttype WxrPost,\n\ttype WxrTag,\n\ttype WxrTerm,\n} from \"emdash\";\nimport type { z } from \"zod\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { handleTaxonomyCreate } from \"#api/handlers/taxonomies.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { wpPluginExecuteBody } from \"#api/schemas.js\";\nimport { BylineRepository } from \"#db/repositories/byline.js\";\nimport { importCommentsFromPlugin } from \"#import/comments.js\";\nimport { getSource } from \"#import/index.js\";\nimport { importMenusFromPlugin } from \"#import/menus.js\";\nimport { importSiteSettings, parseSiteSettingsFromPlugin } from \"#import/settings.js\";\nimport {\n\tfetchPluginComments,\n\tfetchPluginCommentsPage,\n\tfetchPluginContentPage,\n\tfetchPluginMenus,\n\tfetchPluginOptions,\n\tfetchPluginTaxonomies,\n} from \"#import/sources/wordpress-plugin.js\";\nimport { resolveAndValidateExternalUrl, SsrfError } from \"#import/ssrf.js\";\nimport type { ImportConfig, ImportResult, NormalizedItem } from \"#import/types.js\";\nimport { resolveImportByline, sanitizeFieldSlug } from \"#import/utils.js\";\nimport {\n\tattachPostTaxonomies,\n\tloadTaxonomyPlanFromDb,\n\tpreImportWxrTaxonomies,\n\ttype TaxonomyImportPlan,\n} from \"#import/wxr-taxonomies.js\";\nimport type { FieldType } from \"#schema/types.js\";\nimport type { EmDashHandlers, EmDashManifest } from \"#types\";\nimport { slugify } from \"#utils/slugify.js\";\n\nimport { importMediaWithProgress } from \"../wordpress/media.js\";\n\nexport const prerender = false;\n\nexport interface WpPluginImportConfig extends ImportConfig {\n\t/** Author mappings (WP author login -> EmDash user ID) */\n\tauthorMappings?: Record<string, string | null>;\n\t/** Wizard toggles. Absent means enabled (older admins don't send them). */\n\timportMenus?: boolean;\n\timportSiteTitle?: boolean;\n\timportLogo?: boolean;\n\timportSeo?: boolean;\n}\n\nexport interface WpPluginImportResponse {\n\tsuccess: boolean;\n\tresult?: ImportResult;\n\terror?: { message: string };\n}\n\n// =============================================================================\n// Chunked mode (issue #475)\n//\n// A single-invocation import of a large site exceeds Cloudflare Worker\n// resource limits (CPU time, subrequests). In chunked mode the admin drives\n// the import as a loop of bounded requests: one WP content page per call,\n// then paginated comments, then a small finalize step (menus + site\n// identity). Cross-chunk state — the WP-ID -> EmDash-ID map, translation\n// groups, comment threading roots — is accumulated by the client and sent\n// back with each request, so the server stays stateless and an aborted\n// import simply re-runs (skipExisting rebuilds the map while skipping work).\n// =============================================================================\n\n/** Posts per content chunk. 50 posts ≈ a few hundred D1 ops per invocation. */\nconst CONTENT_CHUNK_SIZE = 50;\n\ninterface ChunkCursor {\n\tpostTypeIndex: number;\n\tpage: number;\n}\n\n/** Per-chunk response payload: partial result + state the client must carry. */\ninterface ChunkResponse {\n\tsuccess: boolean;\n\tresult: ImportResult;\n\tdone: boolean;\n\tcursor?: ChunkCursor;\n\tchunk?: {\n\t\tidMap?: Record<string, { id: string; collection: string }>;\n\t\ttranslationGroups?: Record<string, string>;\n\t\tcommentRoots?: Record<string, string>;\n\t};\n}\n\nfunction emptyImportResult(): ImportResult {\n\treturn { success: true, imported: 0, skipped: 0, errors: [], byCollection: {} };\n}\n\nfunction parseIdMap(idMap: Record<string, { id: string; collection: string }> | undefined): {\n\tcontentIdMap: Map<number, string>;\n\tcollectionByWpId: Map<number, string>;\n} {\n\tconst contentIdMap = new Map<number, string>();\n\tconst collectionByWpId = new Map<number, string>();\n\tfor (const [key, value] of Object.entries(idMap ?? {})) {\n\t\tconst wpId = Number(key);\n\t\tif (!Number.isFinite(wpId)) continue;\n\t\tcontentIdMap.set(wpId, value.id);\n\t\tcollectionByWpId.set(wpId, value.collection);\n\t}\n\treturn { contentIdMap, collectionByWpId };\n}\n\nfunction serializeIdMap(\n\tcontentIdMap: Map<number, string>,\n\tcollectionByWpId: Map<number, string>,\n): Record<string, { id: string; collection: string }> {\n\tconst out: Record<string, { id: string; collection: string }> = {};\n\tfor (const [wpId, id] of contentIdMap) {\n\t\tconst collection = collectionByWpId.get(wpId);\n\t\tif (collection) out[String(wpId)] = { id, collection };\n\t}\n\treturn out;\n}\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"import:execute\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleContentCreate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash not configured\", 500);\n\t}\n\n\ttry {\n\t\tconst emdashManifest = await emdash.getManifest();\n\n\t\tconst body = await parseBody(request, wpPluginExecuteBody);\n\t\tif (isParseError(body)) return body;\n\n\t\t// SSRF: reject internal/private network targets. Uses DNS resolution\n\t\t// to catch hostnames that resolve to private addresses.\n\t\ttry {\n\t\t\tawait resolveAndValidateExternalUrl(body.url);\n\t\t} catch (e) {\n\t\t\tconst msg = e instanceof SsrfError ? e.message : \"Invalid URL\";\n\t\t\treturn apiError(\"SSRF_BLOCKED\", msg, 400);\n\t\t}\n\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Zod schema output narrowed to WpPluginImportConfig\n\t\tconst config = body.config as unknown as WpPluginImportConfig;\n\n\t\t// Get the WordPress plugin source\n\t\tconst source = getSource(\"wordpress-plugin\");\n\t\tif (!source) {\n\t\t\treturn apiError(\"NOT_CONFIGURED\", \"WordPress plugin source not available\", 500);\n\t\t}\n\n\t\t// Build the list of post types to fetch\n\t\tconst postTypes = Object.entries(config.postTypeMappings)\n\t\t\t.filter(([_, mapping]) => mapping.enabled)\n\t\t\t.map(([postType]) => postType);\n\n\t\tif (postTypes.length === 0) {\n\t\t\treturn apiError(\"VALIDATION_ERROR\", \"No post types selected for import\", 400);\n\t\t}\n\n\t\tconsole.log(\"[WP Plugin Import] Starting import for:\", body.url);\n\t\tconsole.log(\"[WP Plugin Import] Post types:\", postTypes);\n\n\t\t// Chunked mode: one bounded unit of work per invocation (issue #475).\n\t\tif (body.phase) {\n\t\t\tconst chunk = await runImportPhase(emdash, body, config, postTypes, emdashManifest);\n\t\t\treturn apiSuccess(chunk);\n\t\t}\n\n\t\t// Pre-create taxonomy defs (for custom CPT taxonomies) and terms so\n\t\t// per-post assignments can attach.\n\t\t// Non-fatal: a site whose /taxonomies call fails still gets content.\n\t\tlet taxonomyPlan: TaxonomyImportPlan | undefined;\n\t\tlet taxonomyDefsCreated: string[] = [];\n\t\ttry {\n\t\t\tconst built = await buildTaxonomyPlan(emdash, body.url, body.token, config);\n\t\t\ttaxonomyPlan = built.plan;\n\t\t\ttaxonomyDefsCreated = built.defsCreated;\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Taxonomy pre-import failed:\", e);\n\t\t}\n\n\t\t// Import content (including drafts since we have auth)\n\t\tconst { result, contentIdMap, collectionByWpId } = await importContent(\n\t\t\tsource.fetchContent(\n\t\t\t\t{ type: \"url\", url: body.url, token: body.token },\n\t\t\t\t{ postTypes, includeDrafts: true },\n\t\t\t),\n\t\t\tconfig,\n\t\t\temdash,\n\t\t\temdashManifest,\n\t\t\ttaxonomyPlan,\n\t\t);\n\n\t\t// Import navigation menus, resolving item references through the\n\t\t// WP-post-ID -> EmDash-ID map collected during the content pass.\n\t\tif (config.importMenus !== false) {\n\t\t\tawait importMenusInto(result, emdash, body.url, body.token, contentIdMap);\n\t\t}\n\n\t\t// Import comments into EmDash's native comments table, preserving\n\t\t// authors, dates, threading, and approval status.\n\t\t// Non-fatal: older plugin versions have no /comments endpoint.\n\t\ttry {\n\t\t\tconst comments = await fetchPluginComments(body.url, body.token);\n\t\t\tif (comments.length > 0) {\n\t\t\t\tconst commentsResult = await importCommentsFromPlugin(\n\t\t\t\t\tcomments,\n\t\t\t\t\temdash.db,\n\t\t\t\t\tcontentIdMap,\n\t\t\t\t\tcollectionByWpId,\n\t\t\t\t);\n\t\t\t\tresult.comments = {\n\t\t\t\t\timported: commentsResult.imported,\n\t\t\t\t\tskipped: commentsResult.skipped,\n\t\t\t\t};\n\t\t\t\tfor (const commentError of commentsResult.errors) {\n\t\t\t\t\tresult.errors.push({\n\t\t\t\t\t\ttitle: `Comment: ${commentError.comment}`,\n\t\t\t\t\t\terror: commentError.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Comment import failed:\", e);\n\t\t}\n\n\t\t// Apply site identity (title, tagline, logo, favicon) from the source\n\t\t// site's options, replacing the starter template's seed placeholders.\n\t\t// Non-fatal: content is already imported at this point.\n\t\ttry {\n\t\t\tresult.siteSettings = await applySiteSettings(emdash, body.url, body.token, config);\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Site settings import failed:\", e);\n\t\t}\n\n\t\tif (taxonomyDefsCreated.length > 0) {\n\t\t\tresult.taxonomiesCreated = taxonomyDefsCreated;\n\t\t}\n\n\t\tconsole.log(\"[WP Plugin Import] Import result:\", JSON.stringify(result, null, 2));\n\n\t\treturn apiSuccess({\n\t\t\tsuccess: true,\n\t\t\tresult,\n\t\t});\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to import from WordPress\", \"WP_PLUGIN_IMPORT_ERROR\");\n\t}\n};\n\n/**\n * Import navigation menus into `result`, resolving item references through\n * the WP-post-ID -> EmDash-ID map collected during the content pass.\n * Non-fatal: older plugin versions have no /menus endpoint.\n */\nasync function importMenusInto(\n\tresult: ImportResult,\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tcontentIdMap: Map<number, string>,\n): Promise<void> {\n\ttry {\n\t\tconst menus = await fetchPluginMenus(url, token);\n\t\tif (menus.length > 0) {\n\t\t\tconst menuResult = await importMenusFromPlugin(menus, emdash.db, contentIdMap);\n\t\t\tresult.menus = {\n\t\t\t\tcreated: menuResult.menusCreated,\n\t\t\t\titems: menuResult.itemsCreated,\n\t\t\t};\n\t\t\tfor (const menuError of menuResult.errors) {\n\t\t\t\tresult.errors.push({ title: `Menu: ${menuError.menu}`, error: menuError.error });\n\t\t\t}\n\t\t}\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Menu import failed:\", e);\n\t}\n}\n\ntype ExecuteBody = z.infer<typeof wpPluginExecuteBody>;\n\n/** Dispatch one chunk of work for the requested phase. */\nasync function runImportPhase(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n\tpostTypes: string[],\n\tmanifest: EmDashManifest,\n): Promise<ChunkResponse> {\n\tswitch (body.phase) {\n\t\tcase \"content\":\n\t\t\treturn runContentChunk(emdash, body, config, postTypes, manifest);\n\t\tcase \"comments\":\n\t\t\treturn runCommentsChunk(emdash, body);\n\t\tcase \"finalize\":\n\t\t\treturn runFinalizePhase(emdash, body, config);\n\t\tcase undefined:\n\t\t\tthrow new Error(\"runImportPhase called without a phase\");\n\t\tdefault:\n\t\t\tbody.phase satisfies never;\n\t\t\tthrow new Error(\"Unknown import phase\");\n\t}\n}\n\n/**\n * Import one page of one post type. The first chunk additionally runs the\n * taxonomy setup (def + term creation); later chunks only reload the\n * lookup maps from the database.\n */\nasync function runContentChunk(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n\tpostTypes: string[],\n\tmanifest: EmDashManifest,\n): Promise<ChunkResponse> {\n\tconst cursor = body.cursor ?? { postTypeIndex: 0, page: 1 };\n\tconst postType = postTypes[cursor.postTypeIndex];\n\tif (!postType) {\n\t\treturn { success: true, result: emptyImportResult(), done: true };\n\t}\n\n\tconst isFirstChunk = cursor.postTypeIndex === 0 && cursor.page === 1;\n\tlet taxonomyPlan: TaxonomyImportPlan | undefined;\n\tlet taxonomyDefsCreated: string[] = [];\n\ttry {\n\t\tif (isFirstChunk) {\n\t\t\tconst built = await buildTaxonomyPlan(emdash, body.url, body.token, config);\n\t\t\ttaxonomyPlan = built.plan;\n\t\t\ttaxonomyDefsCreated = built.defsCreated;\n\t\t} else {\n\t\t\ttaxonomyPlan = await loadTaxonomyPlanFromDb(emdash.db);\n\t\t}\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Taxonomy pre-import failed:\", e);\n\t}\n\n\tconst page = await fetchPluginContentPage({\n\t\tsiteUrl: body.url,\n\t\ttoken: body.token,\n\t\tpostType,\n\t\tpage: cursor.page,\n\t\tperPage: CONTENT_CHUNK_SIZE,\n\t\tincludeDrafts: true,\n\t});\n\n\t// Seed translation-group state from earlier chunks so a translation in\n\t// this page links to its sibling imported three chunks ago.\n\tconst translationGroupMap = new Map(Object.entries(body.translationGroups ?? {}));\n\n\tconst { result, contentIdMap, collectionByWpId } = await importContent(\n\t\tpage.items,\n\t\tconfig,\n\t\temdash,\n\t\tmanifest,\n\t\ttaxonomyPlan,\n\t\ttranslationGroupMap,\n\t);\n\n\tif (taxonomyDefsCreated.length > 0) {\n\t\tresult.taxonomiesCreated = taxonomyDefsCreated;\n\t}\n\n\t// Advance: next page of this post type, first page of the next one,\n\t// or done. An empty last page (totalPages can shrink while paginating\n\t// a live site) still terminates because page >= totalPages.\n\tlet next: ChunkCursor | undefined;\n\tif (cursor.page < page.totalPages) {\n\t\tnext = { postTypeIndex: cursor.postTypeIndex, page: cursor.page + 1 };\n\t} else if (cursor.postTypeIndex + 1 < postTypes.length) {\n\t\tnext = { postTypeIndex: cursor.postTypeIndex + 1, page: 1 };\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tresult,\n\t\tdone: next === undefined,\n\t\tcursor: next,\n\t\tchunk: {\n\t\t\tidMap: serializeIdMap(contentIdMap, collectionByWpId),\n\t\t\ttranslationGroups: Object.fromEntries(translationGroupMap),\n\t\t},\n\t};\n}\n\n/**\n * Import one page of comments (500 per page, ordered by WP comment ID so\n * parents precede children across pages). Requires the accumulated idMap\n * from the content phase; threading roots accumulate in `commentRoots`.\n */\nasync function runCommentsChunk(emdash: EmDashHandlers, body: ExecuteBody): Promise<ChunkResponse> {\n\tconst page = body.cursor?.page ?? 1;\n\tconst result = emptyImportResult();\n\n\tconst { contentIdMap, collectionByWpId } = parseIdMap(body.idMap);\n\tconst rootIds = new Map<number, string>();\n\tfor (const [key, value] of Object.entries(body.commentRoots ?? {})) {\n\t\tconst wpId = Number(key);\n\t\tif (Number.isFinite(wpId)) rootIds.set(wpId, value);\n\t}\n\n\tconst { items, totalPages } = await fetchPluginCommentsPage(body.url, body.token, page);\n\n\tif (items.length > 0) {\n\t\tconst commentsResult = await importCommentsFromPlugin(\n\t\t\titems,\n\t\t\temdash.db,\n\t\t\tcontentIdMap,\n\t\t\tcollectionByWpId,\n\t\t\trootIds,\n\t\t);\n\t\tresult.comments = {\n\t\t\timported: commentsResult.imported,\n\t\t\tskipped: commentsResult.skipped,\n\t\t};\n\t\tfor (const commentError of commentsResult.errors) {\n\t\t\tresult.errors.push({ title: `Comment: ${commentError.comment}`, error: commentError.error });\n\t\t}\n\t\tresult.success = result.errors.length === 0;\n\t}\n\n\tconst done = page >= totalPages;\n\tconst commentRoots: Record<string, string> = {};\n\tfor (const [wpId, id] of rootIds) commentRoots[String(wpId)] = id;\n\n\treturn {\n\t\tsuccess: true,\n\t\tresult,\n\t\tdone,\n\t\tcursor: done ? undefined : { postTypeIndex: 0, page: page + 1 },\n\t\tchunk: { commentRoots },\n\t};\n}\n\n/** Menus + site identity — small, runs as a single closing chunk. */\nasync function runFinalizePhase(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n): Promise<ChunkResponse> {\n\tconst result = emptyImportResult();\n\tconst { contentIdMap } = parseIdMap(body.idMap);\n\n\tif (config.importMenus !== false) {\n\t\tawait importMenusInto(result, emdash, body.url, body.token, contentIdMap);\n\t}\n\n\ttry {\n\t\tresult.siteSettings = await applySiteSettings(emdash, body.url, body.token, config);\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Site settings import failed:\", e);\n\t}\n\n\tresult.success = result.errors.length === 0;\n\treturn { success: true, result, done: true };\n}\n\n/** Fields that should be auto-created if they don't exist */\nconst IMPORT_FIELDS: Array<{\n\tslug: string;\n\tlabel: string;\n\ttype: FieldType;\n\tcheck: (item: NormalizedItem) => boolean;\n}> = [\n\t{\n\t\tslug: \"title\",\n\t\tlabel: \"Title\",\n\t\ttype: \"string\",\n\t\tcheck: () => true,\n\t},\n\t{\n\t\tslug: \"content\",\n\t\tlabel: \"Content\",\n\t\ttype: \"portableText\",\n\t\tcheck: () => true,\n\t},\n\t{\n\t\tslug: \"excerpt\",\n\t\tlabel: \"Excerpt\",\n\t\ttype: \"text\",\n\t\tcheck: (item) => !!item.excerpt,\n\t},\n\t{\n\t\tslug: \"featured_image\",\n\t\tlabel: \"Featured Image\",\n\t\ttype: \"image\",\n\t\tcheck: (item) => !!item.featuredImage,\n\t},\n\t{\n\t\tslug: \"seo_title\",\n\t\tlabel: \"SEO Title\",\n\t\ttype: \"string\",\n\t\tcheck: (item) => !!extractSeo(item).title,\n\t},\n\t{\n\t\tslug: \"seo_description\",\n\t\tlabel: \"SEO Description\",\n\t\ttype: \"text\",\n\t\tcheck: (item) => !!extractSeo(item).description,\n\t},\n];\n\nconst SEO_FIELD_SLUGS = new Set([\"seo_title\", \"seo_description\"]);\n\n/**\n * Coerce a WordPress meta value to an EmDash field type. WP postmeta is\n * stringly typed and inconsistent across posts (the same key can hold\n * \"5\", 5, \"\", or false). Returns `undefined` when the value can't\n * reasonably represent the target type — the caller drops it.\n */\nexport function coerceToFieldType(value: unknown, fieldType: string): unknown {\n\tswitch (fieldType) {\n\t\tcase \"integer\": {\n\t\t\tconst n = typeof value === \"number\" ? value : Number(value);\n\t\t\treturn Number.isInteger(n) ? n : undefined;\n\t\t}\n\t\tcase \"number\": {\n\t\t\tconst n = typeof value === \"number\" ? value : Number(value);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\tcase \"boolean\": {\n\t\t\tif (typeof value === \"boolean\") return value;\n\t\t\tif (value === 1 || value === \"1\" || value === \"true\" || value === \"yes\") return true;\n\t\t\tif (value === 0 || value === \"0\" || value === \"false\" || value === \"no\") return false;\n\t\t\treturn undefined;\n\t\t}\n\t\tcase \"datetime\": {\n\t\t\tif (typeof value !== \"string\" && typeof value !== \"number\") return undefined;\n\t\t\tconst d = new Date(value);\n\t\t\treturn Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n\t\t}\n\t\tcase \"json\":\n\t\t\t// Anything serializes; objects/arrays pass through as-is\n\t\t\treturn value;\n\t\tcase \"string\":\n\t\tcase \"text\":\n\t\tcase \"url\":\n\t\tcase \"select\":\n\t\tcase \"slug\":\n\t\tcase \"reference\":\n\t\t\tif (typeof value === \"string\") return value;\n\t\t\tif (typeof value === \"number\") return String(value);\n\t\t\treturn undefined;\n\t\tdefault:\n\t\t\t// Complex types (image, portableText, repeater, multiSelect, file):\n\t\t\t// raw meta can't be coerced reliably -- pass through only if it\n\t\t\t// already has a non-primitive shape.\n\t\t\treturn typeof value === \"object\" ? value : undefined;\n\t}\n}\n\n/**\n * Pull the per-post SEO title/description out of the Yoast / Rank Math\n * blobs the plugin source stashes in `item.meta`. Empty strings mean \"not\n * overridden for this post\" (the plugin exports the raw meta values) and\n * are treated as absent.\n */\nfunction pickSeoValue(blob: unknown, key: string): string | undefined {\n\tif (typeof blob !== \"object\" || blob === null) return undefined;\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed to non-null object above\n\tconst value = (blob as Record<string, unknown>)[key];\n\treturn typeof value === \"string\" && value.trim() !== \"\" ? value : undefined;\n}\n\nfunction extractSeo(item: NormalizedItem): { title?: string; description?: string } {\n\tconst yoast = item.meta?._yoast;\n\tconst rankmath = item.meta?._rankmath;\n\treturn {\n\t\ttitle: pickSeoValue(yoast, \"title\") ?? pickSeoValue(rankmath, \"title\"),\n\t\tdescription: pickSeoValue(yoast, \"description\") ?? pickSeoValue(rankmath, \"description\"),\n\t};\n}\n\n/**\n * Fetch the site's taxonomies from the plugin API and pre-create all terms,\n * reusing the WXR taxonomy machinery (same def-lookup, idempotency, and\n * collection-filter semantics).\n */\n/** WP built-in taxonomies that either map to seeded defs or are not content taxonomies. */\nconst BUILTIN_TAXONOMIES = new Set([\"category\", \"post_tag\", \"nav_menu\", \"post_format\"]);\n\n/** Mirrors NAME_PATTERN in the taxonomy handler -- names that fail stay in missingTaxonomies. */\nconst TAXONOMY_NAME_PATTERN = /^[a-z][a-z0-9_]*$/;\n\n/**\n * Create EmDash taxonomy defs for custom WP taxonomies (e.g. CPT taxonomies\n * like `company` or `plattform`) that don't exist yet, scoped to the\n * collections the enabled post-type mappings target. Returns the names of\n * the defs created. Runs before term pre-import so the terms and per-post\n * assignments flow through the existing machinery instead of being dropped\n * as `missingTaxonomies`.\n */\nexport async function ensureCustomTaxonomyDefs(\n\tdb: EmDashHandlers[\"db\"],\n\ttaxonomies: Awaited<ReturnType<typeof fetchPluginTaxonomies>>,\n\tconfig: WpPluginImportConfig,\n): Promise<string[]> {\n\tconst created: string[] = [];\n\tfor (const taxonomy of taxonomies) {\n\t\tif (BUILTIN_TAXONOMIES.has(taxonomy.name)) continue;\n\t\tif (taxonomy.terms.length === 0) continue;\n\t\tif (!TAXONOMY_NAME_PATTERN.test(taxonomy.name)) continue;\n\n\t\t// handleTaxonomyCreate's duplicate guard is locale-scoped; check\n\t\t// name-wide existence ourselves to stay idempotent on re-runs.\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"name\", \"=\", taxonomy.name)\n\t\t\t.executeTakeFirst();\n\t\tif (existing) continue;\n\n\t\t// Scope the def to the collections the WP post types map onto.\n\t\t// Older plugin versions don't send post_types -> empty list = no\n\t\t// collection filter, which the term machinery treats as \"any\".\n\t\tconst collections = (taxonomy.post_types ?? [])\n\t\t\t.map((postType) => config.postTypeMappings[postType])\n\t\t\t.filter((mapping) => mapping?.enabled)\n\t\t\t.map((mapping) => mapping.collection);\n\n\t\tconst result = await handleTaxonomyCreate(db, {\n\t\t\tname: taxonomy.name,\n\t\t\tlabel: taxonomy.label,\n\t\t\tlabelSingular: taxonomy.label_singular,\n\t\t\thierarchical: taxonomy.hierarchical,\n\t\t\tcollections: [...new Set(collections)],\n\t\t});\n\t\tif (result.success) {\n\t\t\tcreated.push(taxonomy.name);\n\t\t} else {\n\t\t\tconsole.warn(\n\t\t\t\t`[WP Plugin Import] Could not create taxonomy '${taxonomy.name}':`,\n\t\t\t\tresult.error.message,\n\t\t\t);\n\t\t}\n\t}\n\treturn created;\n}\n\nasync function buildTaxonomyPlan(\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tconfig: WpPluginImportConfig,\n): Promise<{ plan: TaxonomyImportPlan; defsCreated: string[] }> {\n\tconst taxonomies = await fetchPluginTaxonomies(url, token);\n\n\tconst defsCreated = await ensureCustomTaxonomyDefs(emdash.db, taxonomies, config);\n\n\tconst categories: WxrCategory[] = [];\n\tconst tags: WxrTag[] = [];\n\tconst terms: WxrTerm[] = [];\n\n\tfor (const taxonomy of taxonomies) {\n\t\tfor (const term of taxonomy.terms) {\n\t\t\tif (taxonomy.name === \"category\") {\n\t\t\t\tcategories.push({ nicename: term.slug, name: term.name, description: term.description });\n\t\t\t} else if (taxonomy.name === \"post_tag\") {\n\t\t\t\ttags.push({ slug: term.slug, name: term.name, description: term.description });\n\t\t\t} else if (taxonomy.name !== \"nav_menu\" && taxonomy.name !== \"post_format\") {\n\t\t\t\tterms.push({\n\t\t\t\t\tid: term.id,\n\t\t\t\t\ttaxonomy: taxonomy.name,\n\t\t\t\t\tslug: term.slug,\n\t\t\t\t\tname: term.name,\n\t\t\t\t\tdescription: term.description,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst plan = await preImportWxrTaxonomies(emdash.db, [], categories, tags, terms, undefined);\n\treturn { plan, defsCreated };\n}\n\n/**\n * Fetch the source site's options and apply its identity (title, tagline,\n * logo, favicon) as EmDash site settings, overwriting seed placeholders.\n * Logo/favicon files are side-loaded into media storage first; the later\n * full media pass dedupes them by content hash.\n *\n * Returns the list of applied setting keys.\n */\nasync function applySiteSettings(\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tconfig: WpPluginImportConfig,\n): Promise<string[]> {\n\tconst wantTitle = config.importSiteTitle !== false;\n\tconst wantLogo = config.importLogo !== false;\n\tif (!wantTitle && !wantLogo) return [];\n\n\tconst options = await fetchPluginOptions(url, token);\n\tconst parsed = parseSiteSettingsFromPlugin(options);\n\tif (!wantTitle) {\n\t\tdelete parsed.title;\n\t\tdelete parsed.tagline;\n\t}\n\tif (!wantLogo) {\n\t\tdelete parsed.logo;\n\t\tdelete parsed.favicon;\n\t}\n\n\tconst media: { logoMediaId?: string; faviconMediaId?: string } = {};\n\tif (emdash.storage && (parsed.logo?.url || parsed.favicon?.url)) {\n\t\tconst attachments = [];\n\t\tif (parsed.logo?.url) {\n\t\t\tattachments.push({ id: parsed.logo.id, url: parsed.logo.url });\n\t\t}\n\t\tif (parsed.favicon?.url && parsed.favicon.url !== parsed.logo?.url) {\n\t\t\tattachments.push({ id: parsed.favicon.id, url: parsed.favicon.url });\n\t\t}\n\t\tconst mediaResult = await importMediaWithProgress(\n\t\t\tattachments,\n\t\t\temdash.db,\n\t\t\temdash.storage,\n\t\t\t() => {},\n\t\t);\n\t\tfor (const item of mediaResult.imported) {\n\t\t\tif (item.originalUrl === parsed.logo?.url) {\n\t\t\t\tmedia.logoMediaId = item.mediaId;\n\t\t\t}\n\t\t\tif (item.originalUrl === parsed.favicon?.url) {\n\t\t\t\tmedia.faviconMediaId = item.mediaId;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst settingsResult = await importSiteSettings(parsed, emdash.db, true, media);\n\tfor (const settingError of settingsResult.errors) {\n\t\tconsole.warn(\n\t\t\t`[WP Plugin Import] Site setting \"${settingError.setting}\" failed:`,\n\t\t\tsettingError.error,\n\t\t);\n\t}\n\treturn settingsResult.applied;\n}\n\n/**\n * Adapt a NormalizedItem's taxonomy assignments to the WxrPost shape the\n * shared attach helper consumes.\n */\nfunction toWxrAssignments(item: NormalizedItem): WxrPost {\n\treturn {\n\t\tcategories: item.categories ?? [],\n\t\ttags: item.tags ?? [],\n\t\tcustomTaxonomies: item.customTaxonomies\n\t\t\t? new Map(Object.entries(item.customTaxonomies))\n\t\t\t: undefined,\n\t\tmeta: new Map(),\n\t};\n}\n\n/** Exported for tests (field auto-creation regression coverage). */\nexport async function importContent(\n\titems: AsyncIterable<NormalizedItem> | Iterable<NormalizedItem>,\n\tconfig: WpPluginImportConfig,\n\temdash: EmDashHandlers,\n\tmanifest: EmDashManifest,\n\ttaxonomyPlan: TaxonomyImportPlan | undefined,\n\tseedTranslationGroups?: Map<string, string>,\n): Promise<{\n\tresult: ImportResult;\n\tcontentIdMap: Map<number, string>;\n\tcollectionByWpId: Map<number, string>;\n}> {\n\tconst result: ImportResult = {\n\t\tsuccess: true,\n\t\timported: 0,\n\t\tskipped: 0,\n\t\terrors: [],\n\t\tbyCollection: {},\n\t};\n\n\t// WP post ID -> EmDash content ID, used to resolve menu item references\n\tconst contentIdMap = new Map<number, string>();\n\n\t// WP post ID -> EmDash collection slug, used by the comment import\n\tconst collectionByWpId = new Map<number, string>();\n\n\t// Create content repository for checking existing items\n\tconst contentRepo = new ContentRepository(emdash.db);\n\tconst bylineRepo = new BylineRepository(emdash.db);\n\tconst bylineCache = new Map<string, string>();\n\tconst schemaRegistry = new SchemaRegistry(emdash.db);\n\n\t// Track which (collection, field) pairs have been ensured. Keyed per\n\t// field, not per collection: a field like seo_title may first be\n\t// needed by the 30th item, and gating on the first item would skip it.\n\tconst ensuredFields = new Set<string>();\n\n\t// Field slug -> type per collection, for mapping custom meta/ACF onto\n\t// real fields (and coercing values to the field's type)\n\tconst fieldTypesByCollection = new Map<string, Map<string, string>>();\n\n\t// Track source translationGroup -> EmDash item ID for translation linking.\n\t// Maps source-side translation group ID to the EmDash ID of the first item\n\t// imported for that group (the default-locale item). The chunked import\n\t// seeds this from earlier chunks so groups can span page boundaries.\n\tconst translationGroupMap = seedTranslationGroups ?? new Map<string, string>();\n\n\tfor await (const item of items) {\n\t\tconsole.log(\"[WP Plugin Import] Processing item:\", {\n\t\t\tsourceId: item.sourceId,\n\t\t\ttitle: item.title,\n\t\t\tpostType: item.postType,\n\t\t\tstatus: item.status,\n\t\t\tcontentBlocks: Array.isArray(item.content) ? item.content.length : 0,\n\t\t\tfeaturedImage: item.featuredImage,\n\t\t\tlocale: item.locale,\n\t\t\ttranslationGroup: item.translationGroup,\n\t\t});\n\n\t\tconst mapping = config.postTypeMappings[item.postType];\n\n\t\t// Skip if not mapped or disabled\n\t\tif (!mapping || !mapping.enabled) {\n\t\t\tresult.skipped++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst collection = mapping.collection;\n\n\t\t// Check if collection exists in manifest\n\t\tif (!manifest?.collections[collection]) {\n\t\t\tresult.errors.push({\n\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\terror: `Collection \"${collection}\" does not exist`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\t// Ensure required fields exist in the collection schema. Checked\n\t\t\t// per field and item (not once per collection): whether a field\n\t\t\t// is needed depends on the item — the first post may have no SEO\n\t\t\t// override while a later one does.\n\t\t\tfor (const field of IMPORT_FIELDS) {\n\t\t\t\tif (config.importSeo === false && SEO_FIELD_SLUGS.has(field.slug)) continue;\n\t\t\t\tconst ensureKey = `${collection}:${field.slug}`;\n\t\t\t\tif (ensuredFields.has(ensureKey) || !field.check(item)) continue;\n\t\t\t\tensuredFields.add(ensureKey);\n\t\t\t\tconst existingField = await schemaRegistry.getField(collection, field.slug);\n\t\t\t\tif (!existingField) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`[WP Plugin Import] Creating missing field \"${field.slug}\" in collection \"${collection}\"`,\n\t\t\t\t\t);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait schemaRegistry.createField(collection, {\n\t\t\t\t\t\t\tslug: field.slug,\n\t\t\t\t\t\t\tlabel: field.label,\n\t\t\t\t\t\t\ttype: field.type,\n\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfieldTypesByCollection.get(collection)?.set(field.slug, field.type);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// Field might already exist from concurrent creation\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`[WP Plugin Import] Field \"${field.slug}\" creation skipped:`,\n\t\t\t\t\t\t\te instanceof Error ? e.message : e,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Load the collection's field types once, so custom meta / ACF\n\t\t\t// values can land in matching schema fields (created by the\n\t\t\t// prepare step or already present).\n\t\t\tlet fieldTypes = fieldTypesByCollection.get(collection);\n\t\t\tif (!fieldTypes) {\n\t\t\t\tfieldTypes = new Map<string, string>();\n\t\t\t\tconst collectionDef = await schemaRegistry.getCollection(collection);\n\t\t\t\tif (collectionDef) {\n\t\t\t\t\tfor (const field of await schemaRegistry.listFields(collectionDef.id)) {\n\t\t\t\t\t\tfieldTypes.set(field.slug, field.type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldTypesByCollection.set(collection, fieldTypes);\n\t\t\t}\n\n\t\t\t// Generate slug from item slug or title\n\t\t\tconst slug = item.slug || slugify(item.title || `post-${item.sourceId}`);\n\n\t\t\t// Check if already exists (idempotency) — locale-aware lookup\n\t\t\tif (config.skipExisting) {\n\t\t\t\tconst existing = await contentRepo.findBySlug(collection, slug, item.locale);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// Still track the translation group mapping for later items\n\t\t\t\t\tif (item.translationGroup) {\n\t\t\t\t\t\ttranslationGroupMap.set(item.translationGroup, existing.id);\n\t\t\t\t\t}\n\t\t\t\t\t// Menus and comments may reference this post even when we skip it\n\t\t\t\t\tconst wpId = Number(item.sourceId);\n\t\t\t\t\tif (Number.isFinite(wpId)) {\n\t\t\t\t\t\tcontentIdMap.set(wpId, existing.id);\n\t\t\t\t\t\tcollectionByWpId.set(wpId, collection);\n\t\t\t\t\t}\n\t\t\t\t\tresult.skipped++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Map WordPress status to EmDash status\n\t\t\tconst status = mapStatus(item.status);\n\n\t\t\t// Build data object - add all applicable fields\n\t\t\tconst data: Record<string, unknown> = {};\n\n\t\t\t// Add standard fields\n\t\t\tdata.title = item.title || \"Untitled\";\n\t\t\tdata.content = item.content;\n\n\t\t\tif (item.excerpt) {\n\t\t\t\tdata.excerpt = item.excerpt;\n\t\t\t}\n\t\t\tif (item.featuredImage) {\n\t\t\t\tdata.featured_image = item.featuredImage;\n\t\t\t\tconsole.log(\"[WP Plugin Import] Adding featured_image:\", item.featuredImage);\n\t\t\t}\n\n\t\t\t// Per-post SEO overrides from Yoast / Rank Math\n\t\t\tif (config.importSeo !== false) {\n\t\t\t\tconst seo = extractSeo(item);\n\t\t\t\tif (seo.title) {\n\t\t\t\t\tdata.seo_title = seo.title;\n\t\t\t\t}\n\t\t\t\tif (seo.description) {\n\t\t\t\t\tdata.seo_description = seo.description;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Map ACF values and custom meta onto schema fields with the same\n\t\t\t// (sanitized) slug — the same sanitization the analysis applied\n\t\t\t// when suggesting the fields, so keys like `event-date` land in\n\t\t\t// the `event_date` field the prepare step created. Values without\n\t\t\t// a matching field are dropped -- the user controls the schema,\n\t\t\t// we don't invent fields per meta key. Values are coerced to the\n\t\t\t// field's type (the analysis inferred it from ONE sample; real\n\t\t\t// values vary) and dropped when incoercible, so one odd meta\n\t\t\t// value can't fail the whole item.\n\t\t\tconst assignMetaValue = (key: string, value: unknown) => {\n\t\t\t\tif (value === null || value === \"\") return;\n\t\t\t\tconst fieldSlug = sanitizeFieldSlug(key);\n\t\t\t\tconst fieldType = fieldTypes.get(fieldSlug);\n\t\t\t\tif (!fieldType || fieldSlug in data) return;\n\t\t\t\tconst coerced = coerceToFieldType(value, fieldType);\n\t\t\t\tif (coerced !== undefined) {\n\t\t\t\t\tdata[fieldSlug] = coerced;\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst acf = item.meta?._acf;\n\t\t\tif (typeof acf === \"object\" && acf !== null) {\n\t\t\t\tfor (const [key, value] of Object.entries(acf)) {\n\t\t\t\t\tassignMetaValue(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.meta) {\n\t\t\t\tfor (const [key, value] of Object.entries(item.meta)) {\n\t\t\t\t\t// Underscore keys are WP-internal or handled above (_acf/_yoast/_rankmath)\n\t\t\t\t\tif (key.startsWith(\"_\")) continue;\n\t\t\t\t\tassignMetaValue(key, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Resolve author ID from mappings\n\t\t\tlet authorId: string | undefined;\n\t\t\tif (config.authorMappings && item.author) {\n\t\t\t\tconst mappedUserId = config.authorMappings[item.author];\n\t\t\t\tif (mappedUserId !== undefined && mappedUserId !== null) {\n\t\t\t\t\tauthorId = mappedUserId;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst bylineId = await resolveImportByline(\n\t\t\t\titem.author,\n\t\t\t\titem.author, // display name fallback is the login\n\t\t\t\tauthorId,\n\t\t\t\tbylineRepo,\n\t\t\t\tbylineCache,\n\t\t\t);\n\n\t\t\t// Resolve translation link: if this item has a translationGroup and\n\t\t\t// we've already imported another item in the same group, link them.\n\t\t\tlet translationOf: string | undefined;\n\t\t\tif (item.translationGroup) {\n\t\t\t\tconst existingGroupItem = translationGroupMap.get(item.translationGroup);\n\t\t\t\tif (existingGroupItem) {\n\t\t\t\t\ttranslationOf = existingGroupItem;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Preserve original dates from the source\n\t\t\tconst itemDateTime = item.date?.getTime();\n\t\t\tconst createdAt =\n\t\t\t\titemDateTime !== undefined && !Number.isNaN(itemDateTime)\n\t\t\t\t\t? item.date.toISOString()\n\t\t\t\t\t: undefined;\n\t\t\tconst publishedAt = status === \"published\" && createdAt ? createdAt : undefined;\n\n\t\t\t// Create the content item\n\t\t\tconst createResult = await emdash.handleContentCreate(collection, {\n\t\t\t\tdata,\n\t\t\t\tslug,\n\t\t\t\tstatus,\n\t\t\t\tauthorId,\n\t\t\t\tbylines: bylineId ? [{ bylineId }] : undefined,\n\t\t\t\tlocale: item.locale,\n\t\t\t\ttranslationOf,\n\t\t\t\tcreatedAt,\n\t\t\t\tpublishedAt,\n\t\t\t});\n\n\t\t\tif (createResult.success) {\n\t\t\t\tresult.imported++;\n\t\t\t\tresult.byCollection[collection] = (result.byCollection[collection] || 0) + 1;\n\n\t\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- create handler returns { item, _rev }\n\t\t\t\tconst createdData = createResult.data as { item?: { id?: string } } | undefined;\n\t\t\t\tconst createdId = createdData?.item?.id;\n\n\t\t\t\tif (createdId) {\n\t\t\t\t\tconst wpId = Number(item.sourceId);\n\t\t\t\t\tif (Number.isFinite(wpId)) {\n\t\t\t\t\t\tcontentIdMap.set(wpId, createdId);\n\t\t\t\t\t\tcollectionByWpId.set(wpId, collection);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Attach category/tag/custom-taxonomy assignments\n\t\t\t\t\tif (taxonomyPlan) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst attached = await attachPostTaxonomies(\n\t\t\t\t\t\t\t\temdash.db,\n\t\t\t\t\t\t\t\tcollection,\n\t\t\t\t\t\t\t\tcreatedId,\n\t\t\t\t\t\t\t\ttoWxrAssignments(item),\n\t\t\t\t\t\t\t\ttaxonomyPlan,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (attached > 0) {\n\t\t\t\t\t\t\t\tresult.taxonomyAssignments = (result.taxonomyAssignments ?? 0) + attached;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tconsole.warn(`[WP Plugin Import] Taxonomy attach failed for \"${slug}\":`, e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track translation group: first item in a group establishes the mapping\n\t\t\t\tif (item.translationGroup && !translationGroupMap.has(item.translationGroup) && createdId) {\n\t\t\t\t\ttranslationGroupMap.set(item.translationGroup, createdId);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult.errors.push({\n\t\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\t\terror:\n\t\t\t\t\t\ttypeof createResult.error === \"object\" && createResult.error !== null\n\t\t\t\t\t\t\t? (createResult.error as { message?: string }).message || \"Unknown error\"\n\t\t\t\t\t\t\t: String(createResult.error),\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(`Import error for \"${item.title || \"Untitled\"}\":`, error);\n\t\t\tresult.errors.push({\n\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\terror: error instanceof Error && error.message ? error.message : \"Failed to import item\",\n\t\t\t});\n\t\t}\n\t}\n\n\tif (taxonomyPlan && taxonomyPlan.missingTaxonomies.length > 0) {\n\t\tresult.missingTaxonomies = taxonomyPlan.missingTaxonomies;\n\t}\n\n\tresult.success = result.errors.length === 0;\n\treturn { result, contentIdMap, collectionByWpId };\n}\n\nfunction mapStatus(wpStatus: string | undefined): string {\n\tswitch (wpStatus) {\n\t\tcase \"publish\":\n\t\t\treturn \"published\";\n\t\tcase \"draft\":\n\t\t\treturn \"draft\";\n\t\tcase \"pending\":\n\t\t\treturn \"draft\";\n\t\tcase \"private\":\n\t\t\treturn \"draft\";\n\t\tdefault:\n\t\t\treturn \"draft\";\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"execute.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/import/wordpress-plugin/execute.ts"],"sourcesContent":["/**\n * WordPress Plugin execute import endpoint\n *\n * POST /_emdash/api/import/wordpress-plugin/execute\n *\n * Imports content from WordPress via EmDash Exporter plugin API.\n */\n\nimport type { APIRoute } from \"astro\";\nimport {\n\tContentRepository,\n\tSchemaRegistry,\n\ttype WxrCategory,\n\ttype WxrPost,\n\ttype WxrTag,\n\ttype WxrTerm,\n} from \"emdash\";\nimport type { z } from \"zod\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { handleTaxonomyCreate } from \"#api/handlers/taxonomies.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { wpPluginExecuteBody } from \"#api/schemas.js\";\nimport { BylineRepository } from \"#db/repositories/byline.js\";\nimport { importCommentsFromPlugin } from \"#import/comments.js\";\nimport { getSource } from \"#import/index.js\";\nimport { importMenusFromPlugin } from \"#import/menus.js\";\nimport { importSiteSettings, parseSiteSettingsFromPlugin } from \"#import/settings.js\";\nimport {\n\tfetchPluginComments,\n\tfetchPluginCommentsPage,\n\tfetchPluginContentPage,\n\tfetchPluginMenus,\n\tfetchPluginOptions,\n\tfetchPluginTaxonomies,\n} from \"#import/sources/wordpress-plugin.js\";\nimport { resolveAndValidateExternalUrl, SsrfError } from \"#import/ssrf.js\";\nimport type { ImportConfig, ImportResult, NormalizedItem } from \"#import/types.js\";\nimport { resolveImportByline, sanitizeFieldSlug } from \"#import/utils.js\";\nimport {\n\tattachPostTaxonomies,\n\tloadTaxonomyPlanFromDb,\n\tpreImportWxrTaxonomies,\n\ttype TaxonomyImportPlan,\n} from \"#import/wxr-taxonomies.js\";\nimport type { FieldType } from \"#schema/types.js\";\nimport type { EmDashHandlers, EmDashManifest } from \"#types\";\nimport { slugify } from \"#utils/slugify.js\";\n\nimport { importMediaWithProgress } from \"../wordpress/media.js\";\n\nexport const prerender = false;\n\nexport interface WpPluginImportConfig extends ImportConfig {\n\t/** Author mappings (WP author login -> EmDash user ID) */\n\tauthorMappings?: Record<string, string | null>;\n\t/** Wizard toggles. Absent means enabled (older admins don't send them). */\n\timportMenus?: boolean;\n\timportSiteTitle?: boolean;\n\timportLogo?: boolean;\n\timportSeo?: boolean;\n}\n\nexport interface WpPluginImportResponse {\n\tsuccess: boolean;\n\tresult?: ImportResult;\n\terror?: { message: string };\n}\n\n// =============================================================================\n// Chunked mode (issue #475)\n//\n// A single-invocation import of a large site exceeds Cloudflare Worker\n// resource limits (CPU time, subrequests). In chunked mode the admin drives\n// the import as a loop of bounded requests: one WP content page per call,\n// then paginated comments, then a small finalize step (menus + site\n// identity). Cross-chunk state — the WP-ID -> EmDash-ID map, translation\n// groups, comment threading roots — is accumulated by the client and sent\n// back with each request, so the server stays stateless and an aborted\n// import simply re-runs (skipExisting rebuilds the map while skipping work).\n// =============================================================================\n\n/** Posts per content chunk. 50 posts ≈ a few hundred D1 ops per invocation. */\nconst CONTENT_CHUNK_SIZE = 50;\n\ninterface ChunkCursor {\n\tpostTypeIndex: number;\n\tpage: number;\n}\n\n/** Per-chunk response payload: partial result + state the client must carry. */\ninterface ChunkResponse {\n\tsuccess: boolean;\n\tresult: ImportResult;\n\tdone: boolean;\n\tcursor?: ChunkCursor;\n\tchunk?: {\n\t\tidMap?: Record<string, { id: string; collection: string }>;\n\t\ttranslationGroups?: Record<string, string>;\n\t\tcommentRoots?: Record<string, string>;\n\t};\n}\n\nfunction emptyImportResult(): ImportResult {\n\treturn { success: true, imported: 0, skipped: 0, errors: [], byCollection: {} };\n}\n\nfunction parseIdMap(idMap: Record<string, { id: string; collection: string }> | undefined): {\n\tcontentIdMap: Map<number, string>;\n\tcollectionByWpId: Map<number, string>;\n} {\n\tconst contentIdMap = new Map<number, string>();\n\tconst collectionByWpId = new Map<number, string>();\n\tfor (const [key, value] of Object.entries(idMap ?? {})) {\n\t\tconst wpId = Number(key);\n\t\tif (!Number.isFinite(wpId)) continue;\n\t\tcontentIdMap.set(wpId, value.id);\n\t\tcollectionByWpId.set(wpId, value.collection);\n\t}\n\treturn { contentIdMap, collectionByWpId };\n}\n\nfunction serializeIdMap(\n\tcontentIdMap: Map<number, string>,\n\tcollectionByWpId: Map<number, string>,\n): Record<string, { id: string; collection: string }> {\n\tconst out: Record<string, { id: string; collection: string }> = {};\n\tfor (const [wpId, id] of contentIdMap) {\n\t\tconst collection = collectionByWpId.get(wpId);\n\t\tif (collection) out[String(wpId)] = { id, collection };\n\t}\n\treturn out;\n}\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"import:execute\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleContentCreate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash not configured\", 500);\n\t}\n\n\ttry {\n\t\tconst emdashManifest = await emdash.getManifest();\n\n\t\tconst body = await parseBody(request, wpPluginExecuteBody);\n\t\tif (isParseError(body)) return body;\n\n\t\t// SSRF: reject internal/private network targets. Uses DNS resolution\n\t\t// to catch hostnames that resolve to private addresses.\n\t\ttry {\n\t\t\tawait resolveAndValidateExternalUrl(body.url);\n\t\t} catch (e) {\n\t\t\tconst msg = e instanceof SsrfError ? e.message : \"Invalid URL\";\n\t\t\treturn apiError(\"SSRF_BLOCKED\", msg, 400);\n\t\t}\n\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Zod schema output narrowed to WpPluginImportConfig\n\t\tconst config = body.config as unknown as WpPluginImportConfig;\n\n\t\t// Get the WordPress plugin source\n\t\tconst source = getSource(\"wordpress-plugin\");\n\t\tif (!source) {\n\t\t\treturn apiError(\"NOT_CONFIGURED\", \"WordPress plugin source not available\", 500);\n\t\t}\n\n\t\t// Build the list of post types to fetch\n\t\tconst postTypes = Object.entries(config.postTypeMappings)\n\t\t\t.filter(([_, mapping]) => mapping.enabled)\n\t\t\t.map(([postType]) => postType);\n\n\t\tif (postTypes.length === 0) {\n\t\t\treturn apiError(\"VALIDATION_ERROR\", \"No post types selected for import\", 400);\n\t\t}\n\n\t\tconsole.log(\"[WP Plugin Import] Starting import for:\", body.url);\n\t\tconsole.log(\"[WP Plugin Import] Post types:\", postTypes);\n\n\t\t// Chunked mode: one bounded unit of work per invocation (issue #475).\n\t\tif (body.phase) {\n\t\t\tconst chunk = await runImportPhase(emdash, body, config, postTypes, emdashManifest);\n\t\t\treturn apiSuccess(chunk);\n\t\t}\n\n\t\t// Pre-create taxonomy defs (for custom CPT taxonomies) and terms so\n\t\t// per-post assignments can attach.\n\t\t// Non-fatal: a site whose /taxonomies call fails still gets content.\n\t\tlet taxonomyPlan: TaxonomyImportPlan | undefined;\n\t\tlet taxonomyDefsCreated: string[] = [];\n\t\ttry {\n\t\t\tconst built = await buildTaxonomyPlan(emdash, body.url, body.token, config);\n\t\t\ttaxonomyPlan = built.plan;\n\t\t\ttaxonomyDefsCreated = built.defsCreated;\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Taxonomy pre-import failed:\", e);\n\t\t}\n\n\t\t// Import content (including drafts since we have auth)\n\t\tconst { result, contentIdMap, collectionByWpId } = await importContent(\n\t\t\tsource.fetchContent(\n\t\t\t\t{ type: \"url\", url: body.url, token: body.token },\n\t\t\t\t{ postTypes, includeDrafts: true },\n\t\t\t),\n\t\t\tconfig,\n\t\t\temdash,\n\t\t\temdashManifest,\n\t\t\ttaxonomyPlan,\n\t\t);\n\n\t\t// Import navigation menus, resolving item references through the\n\t\t// WP-post-ID -> EmDash-ID map collected during the content pass.\n\t\tif (config.importMenus !== false) {\n\t\t\tawait importMenusInto(result, emdash, body.url, body.token, contentIdMap);\n\t\t}\n\n\t\t// Import comments into EmDash's native comments table, preserving\n\t\t// authors, dates, threading, and approval status.\n\t\t// Non-fatal: older plugin versions have no /comments endpoint.\n\t\ttry {\n\t\t\tconst comments = await fetchPluginComments(body.url, body.token);\n\t\t\tif (comments.length > 0) {\n\t\t\t\tconst commentsResult = await importCommentsFromPlugin(\n\t\t\t\t\tcomments,\n\t\t\t\t\temdash.db,\n\t\t\t\t\tcontentIdMap,\n\t\t\t\t\tcollectionByWpId,\n\t\t\t\t);\n\t\t\t\tresult.comments = {\n\t\t\t\t\timported: commentsResult.imported,\n\t\t\t\t\tskipped: commentsResult.skipped,\n\t\t\t\t};\n\t\t\t\tfor (const commentError of commentsResult.errors) {\n\t\t\t\t\tresult.errors.push({\n\t\t\t\t\t\ttitle: `Comment: ${commentError.comment}`,\n\t\t\t\t\t\terror: commentError.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Comment import failed:\", e);\n\t\t}\n\n\t\t// Apply site identity (title, tagline, logo, favicon) from the source\n\t\t// site's options, replacing the starter template's seed placeholders.\n\t\t// Non-fatal: content is already imported at this point.\n\t\ttry {\n\t\t\tresult.siteSettings = await applySiteSettings(emdash, body.url, body.token, config);\n\t\t} catch (e) {\n\t\t\tconsole.warn(\"[WP Plugin Import] Site settings import failed:\", e);\n\t\t}\n\n\t\tif (taxonomyDefsCreated.length > 0) {\n\t\t\tresult.taxonomiesCreated = taxonomyDefsCreated;\n\t\t}\n\n\t\tconsole.log(\"[WP Plugin Import] Import result:\", JSON.stringify(result, null, 2));\n\n\t\treturn apiSuccess({\n\t\t\tsuccess: true,\n\t\t\tresult,\n\t\t});\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to import from WordPress\", \"WP_PLUGIN_IMPORT_ERROR\");\n\t}\n};\n\n/**\n * Import navigation menus into `result`, resolving item references through\n * the WP-post-ID -> EmDash-ID map collected during the content pass.\n * Non-fatal: older plugin versions have no /menus endpoint.\n */\nasync function importMenusInto(\n\tresult: ImportResult,\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tcontentIdMap: Map<number, string>,\n): Promise<void> {\n\ttry {\n\t\tconst menus = await fetchPluginMenus(url, token);\n\t\tif (menus.length > 0) {\n\t\t\tconst menuResult = await importMenusFromPlugin(menus, emdash.db, contentIdMap);\n\t\t\tresult.menus = {\n\t\t\t\tcreated: menuResult.menusCreated,\n\t\t\t\titems: menuResult.itemsCreated,\n\t\t\t};\n\t\t\tfor (const menuError of menuResult.errors) {\n\t\t\t\tresult.errors.push({ title: `Menu: ${menuError.menu}`, error: menuError.error });\n\t\t\t}\n\t\t}\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Menu import failed:\", e);\n\t}\n}\n\ntype ExecuteBody = z.infer<typeof wpPluginExecuteBody>;\n\n/** Dispatch one chunk of work for the requested phase. */\nasync function runImportPhase(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n\tpostTypes: string[],\n\tmanifest: EmDashManifest,\n): Promise<ChunkResponse> {\n\tswitch (body.phase) {\n\t\tcase \"content\":\n\t\t\treturn runContentChunk(emdash, body, config, postTypes, manifest);\n\t\tcase \"comments\":\n\t\t\treturn runCommentsChunk(emdash, body);\n\t\tcase \"finalize\":\n\t\t\treturn runFinalizePhase(emdash, body, config);\n\t\tcase undefined:\n\t\t\tthrow new Error(\"runImportPhase called without a phase\");\n\t\tdefault:\n\t\t\tbody.phase satisfies never;\n\t\t\tthrow new Error(\"Unknown import phase\");\n\t}\n}\n\n/**\n * Import one page of one post type. The first chunk additionally runs the\n * taxonomy setup (def + term creation); later chunks only reload the\n * lookup maps from the database.\n */\nasync function runContentChunk(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n\tpostTypes: string[],\n\tmanifest: EmDashManifest,\n): Promise<ChunkResponse> {\n\tconst cursor = body.cursor ?? { postTypeIndex: 0, page: 1 };\n\tconst postType = postTypes[cursor.postTypeIndex];\n\tif (!postType) {\n\t\treturn { success: true, result: emptyImportResult(), done: true };\n\t}\n\n\tconst isFirstChunk = cursor.postTypeIndex === 0 && cursor.page === 1;\n\tlet taxonomyPlan: TaxonomyImportPlan | undefined;\n\tlet taxonomyDefsCreated: string[] = [];\n\ttry {\n\t\tif (isFirstChunk) {\n\t\t\tconst built = await buildTaxonomyPlan(emdash, body.url, body.token, config);\n\t\t\ttaxonomyPlan = built.plan;\n\t\t\ttaxonomyDefsCreated = built.defsCreated;\n\t\t} else {\n\t\t\ttaxonomyPlan = await loadTaxonomyPlanFromDb(emdash.db);\n\t\t}\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Taxonomy pre-import failed:\", e);\n\t}\n\n\tconst page = await fetchPluginContentPage({\n\t\tsiteUrl: body.url,\n\t\ttoken: body.token,\n\t\tpostType,\n\t\tpage: cursor.page,\n\t\tperPage: CONTENT_CHUNK_SIZE,\n\t\tincludeDrafts: true,\n\t});\n\n\t// Seed translation-group state from earlier chunks so a translation in\n\t// this page links to its sibling imported three chunks ago.\n\tconst translationGroupMap = new Map(Object.entries(body.translationGroups ?? {}));\n\n\tconst { result, contentIdMap, collectionByWpId } = await importContent(\n\t\tpage.items,\n\t\tconfig,\n\t\temdash,\n\t\tmanifest,\n\t\ttaxonomyPlan,\n\t\ttranslationGroupMap,\n\t);\n\n\tif (taxonomyDefsCreated.length > 0) {\n\t\tresult.taxonomiesCreated = taxonomyDefsCreated;\n\t}\n\n\t// Advance: next page of this post type, first page of the next one,\n\t// or done. An empty last page (totalPages can shrink while paginating\n\t// a live site) still terminates because page >= totalPages.\n\tlet next: ChunkCursor | undefined;\n\tif (cursor.page < page.totalPages) {\n\t\tnext = { postTypeIndex: cursor.postTypeIndex, page: cursor.page + 1 };\n\t} else if (cursor.postTypeIndex + 1 < postTypes.length) {\n\t\tnext = { postTypeIndex: cursor.postTypeIndex + 1, page: 1 };\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tresult,\n\t\tdone: next === undefined,\n\t\tcursor: next,\n\t\tchunk: {\n\t\t\tidMap: serializeIdMap(contentIdMap, collectionByWpId),\n\t\t\ttranslationGroups: Object.fromEntries(translationGroupMap),\n\t\t},\n\t};\n}\n\n/**\n * Import one page of comments (500 per page, ordered by WP comment ID so\n * parents precede children across pages). Requires the accumulated idMap\n * from the content phase; threading roots accumulate in `commentRoots`.\n */\nasync function runCommentsChunk(emdash: EmDashHandlers, body: ExecuteBody): Promise<ChunkResponse> {\n\tconst page = body.cursor?.page ?? 1;\n\tconst result = emptyImportResult();\n\n\tconst { contentIdMap, collectionByWpId } = parseIdMap(body.idMap);\n\tconst rootIds = new Map<number, string>();\n\tfor (const [key, value] of Object.entries(body.commentRoots ?? {})) {\n\t\tconst wpId = Number(key);\n\t\tif (Number.isFinite(wpId)) rootIds.set(wpId, value);\n\t}\n\n\tconst { items, totalPages } = await fetchPluginCommentsPage(body.url, body.token, page);\n\n\tif (items.length > 0) {\n\t\tconst commentsResult = await importCommentsFromPlugin(\n\t\t\titems,\n\t\t\temdash.db,\n\t\t\tcontentIdMap,\n\t\t\tcollectionByWpId,\n\t\t\trootIds,\n\t\t);\n\t\tresult.comments = {\n\t\t\timported: commentsResult.imported,\n\t\t\tskipped: commentsResult.skipped,\n\t\t};\n\t\tfor (const commentError of commentsResult.errors) {\n\t\t\tresult.errors.push({ title: `Comment: ${commentError.comment}`, error: commentError.error });\n\t\t}\n\t\tresult.success = result.errors.length === 0;\n\t}\n\n\tconst done = page >= totalPages;\n\tconst commentRoots: Record<string, string> = {};\n\tfor (const [wpId, id] of rootIds) commentRoots[String(wpId)] = id;\n\n\treturn {\n\t\tsuccess: true,\n\t\tresult,\n\t\tdone,\n\t\tcursor: done ? undefined : { postTypeIndex: 0, page: page + 1 },\n\t\tchunk: { commentRoots },\n\t};\n}\n\n/** Menus + site identity — small, runs as a single closing chunk. */\nasync function runFinalizePhase(\n\temdash: EmDashHandlers,\n\tbody: ExecuteBody,\n\tconfig: WpPluginImportConfig,\n): Promise<ChunkResponse> {\n\tconst result = emptyImportResult();\n\tconst { contentIdMap } = parseIdMap(body.idMap);\n\n\tif (config.importMenus !== false) {\n\t\tawait importMenusInto(result, emdash, body.url, body.token, contentIdMap);\n\t}\n\n\ttry {\n\t\tresult.siteSettings = await applySiteSettings(emdash, body.url, body.token, config);\n\t} catch (e) {\n\t\tconsole.warn(\"[WP Plugin Import] Site settings import failed:\", e);\n\t}\n\n\tresult.success = result.errors.length === 0;\n\treturn { success: true, result, done: true };\n}\n\n/** Fields that should be auto-created if they don't exist */\nconst IMPORT_FIELDS: Array<{\n\tslug: string;\n\tlabel: string;\n\ttype: FieldType;\n\tcheck: (item: NormalizedItem) => boolean;\n}> = [\n\t{\n\t\tslug: \"title\",\n\t\tlabel: \"Title\",\n\t\ttype: \"string\",\n\t\tcheck: () => true,\n\t},\n\t{\n\t\tslug: \"content\",\n\t\tlabel: \"Content\",\n\t\ttype: \"portableText\",\n\t\tcheck: () => true,\n\t},\n\t{\n\t\tslug: \"excerpt\",\n\t\tlabel: \"Excerpt\",\n\t\ttype: \"text\",\n\t\tcheck: (item) => !!item.excerpt,\n\t},\n\t{\n\t\tslug: \"featured_image\",\n\t\tlabel: \"Featured Image\",\n\t\ttype: \"image\",\n\t\tcheck: (item) => !!item.featuredImage,\n\t},\n\t{\n\t\tslug: \"seo_title\",\n\t\tlabel: \"SEO Title\",\n\t\ttype: \"string\",\n\t\tcheck: (item) => !!extractSeo(item).title,\n\t},\n\t{\n\t\tslug: \"seo_description\",\n\t\tlabel: \"SEO Description\",\n\t\ttype: \"text\",\n\t\tcheck: (item) => !!extractSeo(item).description,\n\t},\n];\n\nconst SEO_FIELD_SLUGS = new Set([\"seo_title\", \"seo_description\"]);\n\n/**\n * Coerce a WordPress meta value to an EmDash field type. WP postmeta is\n * stringly typed and inconsistent across posts (the same key can hold\n * \"5\", 5, \"\", or false). Returns `undefined` when the value can't\n * reasonably represent the target type — the caller drops it.\n */\nexport function coerceToFieldType(value: unknown, fieldType: string): unknown {\n\tswitch (fieldType) {\n\t\tcase \"integer\": {\n\t\t\tconst n = typeof value === \"number\" ? value : Number(value);\n\t\t\treturn Number.isInteger(n) ? n : undefined;\n\t\t}\n\t\tcase \"number\": {\n\t\t\tconst n = typeof value === \"number\" ? value : Number(value);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\tcase \"boolean\": {\n\t\t\tif (typeof value === \"boolean\") return value;\n\t\t\tif (value === 1 || value === \"1\" || value === \"true\" || value === \"yes\") return true;\n\t\t\tif (value === 0 || value === \"0\" || value === \"false\" || value === \"no\") return false;\n\t\t\treturn undefined;\n\t\t}\n\t\tcase \"datetime\": {\n\t\t\tif (typeof value !== \"string\" && typeof value !== \"number\") return undefined;\n\t\t\tconst d = new Date(value);\n\t\t\treturn Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n\t\t}\n\t\tcase \"json\":\n\t\t\t// Anything serializes; objects/arrays pass through as-is\n\t\t\treturn value;\n\t\tcase \"string\":\n\t\tcase \"text\":\n\t\tcase \"url\":\n\t\tcase \"select\":\n\t\tcase \"slug\":\n\t\tcase \"reference\":\n\t\t\tif (typeof value === \"string\") return value;\n\t\t\tif (typeof value === \"number\") return String(value);\n\t\t\treturn undefined;\n\t\tdefault:\n\t\t\t// Complex types (image, portableText, repeater, multiSelect, file):\n\t\t\t// raw meta can't be coerced reliably -- pass through only if it\n\t\t\t// already has a non-primitive shape.\n\t\t\treturn typeof value === \"object\" ? value : undefined;\n\t}\n}\n\n/**\n * Pull the per-post SEO title/description out of the Yoast / Rank Math\n * blobs the plugin source stashes in `item.meta`. Empty strings mean \"not\n * overridden for this post\" (the plugin exports the raw meta values) and\n * are treated as absent.\n */\nfunction pickSeoValue(blob: unknown, key: string): string | undefined {\n\tif (typeof blob !== \"object\" || blob === null) return undefined;\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed to non-null object above\n\tconst value = (blob as Record<string, unknown>)[key];\n\treturn typeof value === \"string\" && value.trim() !== \"\" ? value : undefined;\n}\n\nfunction extractSeo(item: NormalizedItem): { title?: string; description?: string } {\n\tconst yoast = item.meta?._yoast;\n\tconst rankmath = item.meta?._rankmath;\n\treturn {\n\t\ttitle: pickSeoValue(yoast, \"title\") ?? pickSeoValue(rankmath, \"title\"),\n\t\tdescription: pickSeoValue(yoast, \"description\") ?? pickSeoValue(rankmath, \"description\"),\n\t};\n}\n\n/**\n * Fetch the site's taxonomies from the plugin API and pre-create all terms,\n * reusing the WXR taxonomy machinery (same def-lookup, idempotency, and\n * collection-filter semantics).\n */\n/** WP built-in taxonomies that either map to seeded defs or are not content taxonomies. */\nconst BUILTIN_TAXONOMIES = new Set([\"category\", \"post_tag\", \"nav_menu\", \"post_format\"]);\n\n/** Mirrors NAME_PATTERN in the taxonomy handler -- names that fail stay in missingTaxonomies. */\nconst TAXONOMY_NAME_PATTERN = /^[a-z][a-z0-9_]*$/;\n\n/**\n * Create EmDash taxonomy defs for custom WP taxonomies (e.g. CPT taxonomies\n * like `company` or `plattform`) that don't exist yet, scoped to the\n * collections the enabled post-type mappings target. Returns the names of\n * the defs created. Runs before term pre-import so the terms and per-post\n * assignments flow through the existing machinery instead of being dropped\n * as `missingTaxonomies`.\n */\nexport async function ensureCustomTaxonomyDefs(\n\tdb: EmDashHandlers[\"db\"],\n\ttaxonomies: Awaited<ReturnType<typeof fetchPluginTaxonomies>>,\n\tconfig: WpPluginImportConfig,\n): Promise<string[]> {\n\tconst created: string[] = [];\n\tfor (const taxonomy of taxonomies) {\n\t\tif (BUILTIN_TAXONOMIES.has(taxonomy.name)) continue;\n\t\tif (taxonomy.terms.length === 0) continue;\n\t\tif (!TAXONOMY_NAME_PATTERN.test(taxonomy.name)) continue;\n\n\t\t// handleTaxonomyCreate's duplicate guard is locale-scoped; check\n\t\t// name-wide existence ourselves to stay idempotent on re-runs.\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"name\", \"=\", taxonomy.name)\n\t\t\t.executeTakeFirst();\n\t\tif (existing) continue;\n\n\t\t// Scope the def to the collections the WP post types map onto.\n\t\t// Older plugin versions don't send post_types -> empty list = no\n\t\t// collection filter, which the term machinery treats as \"any\".\n\t\tconst collections = (taxonomy.post_types ?? [])\n\t\t\t.map((postType) => config.postTypeMappings[postType])\n\t\t\t.filter((mapping) => mapping?.enabled)\n\t\t\t.map((mapping) => mapping.collection);\n\n\t\tconst result = await handleTaxonomyCreate(db, {\n\t\t\tname: taxonomy.name,\n\t\t\tlabel: taxonomy.label,\n\t\t\tlabelSingular: taxonomy.label_singular,\n\t\t\thierarchical: taxonomy.hierarchical,\n\t\t\tcollections: [...new Set(collections)],\n\t\t});\n\t\tif (result.success) {\n\t\t\tcreated.push(taxonomy.name);\n\t\t} else {\n\t\t\tconsole.warn(\n\t\t\t\t`[WP Plugin Import] Could not create taxonomy '${taxonomy.name}':`,\n\t\t\t\tresult.error.message,\n\t\t\t);\n\t\t}\n\t}\n\treturn created;\n}\n\nasync function buildTaxonomyPlan(\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tconfig: WpPluginImportConfig,\n): Promise<{ plan: TaxonomyImportPlan; defsCreated: string[] }> {\n\tconst taxonomies = await fetchPluginTaxonomies(url, token);\n\n\tconst defsCreated = await ensureCustomTaxonomyDefs(emdash.db, taxonomies, config);\n\n\tconst categories: WxrCategory[] = [];\n\tconst tags: WxrTag[] = [];\n\tconst terms: WxrTerm[] = [];\n\n\tfor (const taxonomy of taxonomies) {\n\t\tfor (const term of taxonomy.terms) {\n\t\t\tif (taxonomy.name === \"category\") {\n\t\t\t\tcategories.push({ nicename: term.slug, name: term.name, description: term.description });\n\t\t\t} else if (taxonomy.name === \"post_tag\") {\n\t\t\t\ttags.push({ slug: term.slug, name: term.name, description: term.description });\n\t\t\t} else if (taxonomy.name !== \"nav_menu\" && taxonomy.name !== \"post_format\") {\n\t\t\t\tterms.push({\n\t\t\t\t\tid: term.id,\n\t\t\t\t\ttaxonomy: taxonomy.name,\n\t\t\t\t\tslug: term.slug,\n\t\t\t\t\tname: term.name,\n\t\t\t\t\tdescription: term.description,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst plan = await preImportWxrTaxonomies(emdash.db, [], categories, tags, terms, undefined);\n\treturn { plan, defsCreated };\n}\n\n/**\n * Fetch the source site's options and apply its identity (title, tagline,\n * logo, favicon) as EmDash site settings, overwriting seed placeholders.\n * Logo/favicon files are side-loaded into media storage first; the later\n * full media pass dedupes them by content hash.\n *\n * Returns the list of applied setting keys.\n */\nasync function applySiteSettings(\n\temdash: EmDashHandlers,\n\turl: string,\n\ttoken: string,\n\tconfig: WpPluginImportConfig,\n): Promise<string[]> {\n\tconst wantTitle = config.importSiteTitle !== false;\n\tconst wantLogo = config.importLogo !== false;\n\tif (!wantTitle && !wantLogo) return [];\n\n\tconst options = await fetchPluginOptions(url, token);\n\tconst parsed = parseSiteSettingsFromPlugin(options);\n\tif (!wantTitle) {\n\t\tdelete parsed.title;\n\t\tdelete parsed.tagline;\n\t}\n\tif (!wantLogo) {\n\t\tdelete parsed.logo;\n\t\tdelete parsed.favicon;\n\t}\n\n\tconst media: { logoMediaId?: string; faviconMediaId?: string } = {};\n\tif (emdash.storage && (parsed.logo?.url || parsed.favicon?.url)) {\n\t\tconst attachments = [];\n\t\tif (parsed.logo?.url) {\n\t\t\tattachments.push({ id: parsed.logo.id, url: parsed.logo.url });\n\t\t}\n\t\tif (parsed.favicon?.url && parsed.favicon.url !== parsed.logo?.url) {\n\t\t\tattachments.push({ id: parsed.favicon.id, url: parsed.favicon.url });\n\t\t}\n\t\tconst mediaResult = await importMediaWithProgress(\n\t\t\tattachments,\n\t\t\temdash.db,\n\t\t\temdash.storage,\n\t\t\t() => {},\n\t\t);\n\t\tfor (const item of mediaResult.imported) {\n\t\t\tif (item.originalUrl === parsed.logo?.url) {\n\t\t\t\tmedia.logoMediaId = item.mediaId;\n\t\t\t}\n\t\t\tif (item.originalUrl === parsed.favicon?.url) {\n\t\t\t\tmedia.faviconMediaId = item.mediaId;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst settingsResult = await importSiteSettings(parsed, emdash.db, true, media);\n\tfor (const settingError of settingsResult.errors) {\n\t\tconsole.warn(\n\t\t\t`[WP Plugin Import] Site setting \"${settingError.setting}\" failed:`,\n\t\t\tsettingError.error,\n\t\t);\n\t}\n\treturn settingsResult.applied;\n}\n\n/**\n * Adapt a NormalizedItem's taxonomy assignments to the WxrPost shape the\n * shared attach helper consumes.\n */\nfunction toWxrAssignments(item: NormalizedItem): WxrPost {\n\treturn {\n\t\tcategories: item.categories ?? [],\n\t\ttags: item.tags ?? [],\n\t\tcustomTaxonomies: item.customTaxonomies\n\t\t\t? new Map(Object.entries(item.customTaxonomies))\n\t\t\t: undefined,\n\t\tmeta: new Map(),\n\t};\n}\n\n/** Exported for tests (field auto-creation regression coverage). */\nexport async function importContent(\n\titems: AsyncIterable<NormalizedItem> | Iterable<NormalizedItem>,\n\tconfig: WpPluginImportConfig,\n\temdash: EmDashHandlers,\n\tmanifest: EmDashManifest,\n\ttaxonomyPlan: TaxonomyImportPlan | undefined,\n\tseedTranslationGroups?: Map<string, string>,\n): Promise<{\n\tresult: ImportResult;\n\tcontentIdMap: Map<number, string>;\n\tcollectionByWpId: Map<number, string>;\n}> {\n\tconst result: ImportResult = {\n\t\tsuccess: true,\n\t\timported: 0,\n\t\tskipped: 0,\n\t\terrors: [],\n\t\tbyCollection: {},\n\t};\n\n\t// WP post ID -> EmDash content ID, used to resolve menu item references\n\tconst contentIdMap = new Map<number, string>();\n\n\t// WP post ID -> EmDash collection slug, used by the comment import\n\tconst collectionByWpId = new Map<number, string>();\n\n\t// Create content repository for checking existing items\n\tconst contentRepo = new ContentRepository(emdash.db);\n\tconst bylineRepo = new BylineRepository(emdash.db);\n\tconst bylineCache = new Map<string, string>();\n\tconst schemaRegistry = new SchemaRegistry(emdash.db);\n\n\t// Track which (collection, field) pairs have been ensured. Keyed per\n\t// field, not per collection: a field like seo_title may first be\n\t// needed by the 30th item, and gating on the first item would skip it.\n\tconst ensuredFields = new Set<string>();\n\n\t// Field slug -> type per collection, for mapping custom meta/ACF onto\n\t// real fields (and coercing values to the field's type)\n\tconst fieldTypesByCollection = new Map<string, Map<string, string>>();\n\n\t// Track source translationGroup -> EmDash item ID for translation linking.\n\t// Maps source-side translation group ID to the EmDash ID of the first item\n\t// imported for that group (the default-locale item). The chunked import\n\t// seeds this from earlier chunks so groups can span page boundaries.\n\tconst translationGroupMap = seedTranslationGroups ?? new Map<string, string>();\n\n\tfor await (const item of items) {\n\t\tconsole.log(\"[WP Plugin Import] Processing item:\", {\n\t\t\tsourceId: item.sourceId,\n\t\t\ttitle: item.title,\n\t\t\tpostType: item.postType,\n\t\t\tstatus: item.status,\n\t\t\tcontentBlocks: Array.isArray(item.content) ? item.content.length : 0,\n\t\t\tfeaturedImage: item.featuredImage,\n\t\t\tlocale: item.locale,\n\t\t\ttranslationGroup: item.translationGroup,\n\t\t});\n\n\t\tconst mapping = config.postTypeMappings[item.postType];\n\n\t\t// Skip if not mapped or disabled\n\t\tif (!mapping || !mapping.enabled) {\n\t\t\tresult.skipped++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst collection = mapping.collection;\n\n\t\t// Check if collection exists in manifest\n\t\tif (!manifest?.collections[collection]) {\n\t\t\tresult.errors.push({\n\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\terror: `Collection \"${collection}\" does not exist`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\t// Ensure required fields exist in the collection schema. Checked\n\t\t\t// per field and item (not once per collection): whether a field\n\t\t\t// is needed depends on the item — the first post may have no SEO\n\t\t\t// override while a later one does.\n\t\t\tfor (const field of IMPORT_FIELDS) {\n\t\t\t\tif (config.importSeo === false && SEO_FIELD_SLUGS.has(field.slug)) continue;\n\t\t\t\tconst ensureKey = `${collection}:${field.slug}`;\n\t\t\t\tif (ensuredFields.has(ensureKey) || !field.check(item)) continue;\n\t\t\t\tensuredFields.add(ensureKey);\n\t\t\t\tconst existingField = await schemaRegistry.getField(collection, field.slug);\n\t\t\t\tif (!existingField) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`[WP Plugin Import] Creating missing field \"${field.slug}\" in collection \"${collection}\"`,\n\t\t\t\t\t);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait schemaRegistry.createField(collection, {\n\t\t\t\t\t\t\tslug: field.slug,\n\t\t\t\t\t\t\tlabel: field.label,\n\t\t\t\t\t\t\ttype: field.type,\n\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfieldTypesByCollection.get(collection)?.set(field.slug, field.type);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// Field might already exist from concurrent creation\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`[WP Plugin Import] Field \"${field.slug}\" creation skipped:`,\n\t\t\t\t\t\t\te instanceof Error ? e.message : e,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Load the collection's field types once, so custom meta / ACF\n\t\t\t// values can land in matching schema fields (created by the\n\t\t\t// prepare step or already present).\n\t\t\tlet fieldTypes = fieldTypesByCollection.get(collection);\n\t\t\tif (!fieldTypes) {\n\t\t\t\tfieldTypes = new Map<string, string>();\n\t\t\t\tconst collectionDef = await schemaRegistry.getCollection(collection);\n\t\t\t\tif (collectionDef) {\n\t\t\t\t\tfor (const field of await schemaRegistry.listFields(collectionDef.id)) {\n\t\t\t\t\t\tfieldTypes.set(field.slug, field.type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldTypesByCollection.set(collection, fieldTypes);\n\t\t\t}\n\n\t\t\t// Generate slug from item slug or title\n\t\t\tconst slug = item.slug || slugify(item.title || `post-${item.sourceId}`);\n\n\t\t\t// Check if already exists (idempotency) — locale-aware lookup\n\t\t\tif (config.skipExisting) {\n\t\t\t\tconst existing = await contentRepo.findBySlug(collection, slug, item.locale);\n\t\t\t\tif (existing) {\n\t\t\t\t\t// Still track the translation group mapping for later items\n\t\t\t\t\tif (item.translationGroup) {\n\t\t\t\t\t\ttranslationGroupMap.set(item.translationGroup, existing.id);\n\t\t\t\t\t}\n\t\t\t\t\t// Menus and comments may reference this post even when we skip it\n\t\t\t\t\tconst wpId = Number(item.sourceId);\n\t\t\t\t\tif (Number.isFinite(wpId)) {\n\t\t\t\t\t\tcontentIdMap.set(wpId, existing.id);\n\t\t\t\t\t\tcollectionByWpId.set(wpId, collection);\n\t\t\t\t\t}\n\t\t\t\t\tresult.skipped++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Map WordPress status to EmDash status\n\t\t\tconst status = mapStatus(item.status);\n\n\t\t\t// Build data object - add all applicable fields\n\t\t\tconst data: Record<string, unknown> = {};\n\n\t\t\t// Add standard fields\n\t\t\tdata.title = item.title || \"Untitled\";\n\t\t\tdata.content = item.content;\n\n\t\t\tif (item.excerpt) {\n\t\t\t\tdata.excerpt = item.excerpt;\n\t\t\t}\n\t\t\tif (item.featuredImage) {\n\t\t\t\tdata.featured_image = item.featuredImage;\n\t\t\t\tconsole.log(\"[WP Plugin Import] Adding featured_image:\", item.featuredImage);\n\t\t\t}\n\n\t\t\t// Per-post SEO overrides from Yoast / Rank Math\n\t\t\tif (config.importSeo !== false) {\n\t\t\t\tconst seo = extractSeo(item);\n\t\t\t\tif (seo.title) {\n\t\t\t\t\tdata.seo_title = seo.title;\n\t\t\t\t}\n\t\t\t\tif (seo.description) {\n\t\t\t\t\tdata.seo_description = seo.description;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Map ACF values and custom meta onto schema fields with the same\n\t\t\t// (sanitized) slug — the same sanitization the analysis applied\n\t\t\t// when suggesting the fields, so keys like `event-date` land in\n\t\t\t// the `event_date` field the prepare step created. Values without\n\t\t\t// a matching field are dropped -- the user controls the schema,\n\t\t\t// we don't invent fields per meta key. Values are coerced to the\n\t\t\t// field's type (the analysis inferred it from ONE sample; real\n\t\t\t// values vary) and dropped when incoercible, so one odd meta\n\t\t\t// value can't fail the whole item.\n\t\t\tconst assignMetaValue = (key: string, value: unknown) => {\n\t\t\t\tif (value === null || value === \"\") return;\n\t\t\t\tconst fieldSlug = sanitizeFieldSlug(key);\n\t\t\t\tconst fieldType = fieldTypes.get(fieldSlug);\n\t\t\t\tif (!fieldType || fieldSlug in data) return;\n\t\t\t\tconst coerced = coerceToFieldType(value, fieldType);\n\t\t\t\tif (coerced !== undefined) {\n\t\t\t\t\tdata[fieldSlug] = coerced;\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst acf = item.meta?._acf;\n\t\t\tif (typeof acf === \"object\" && acf !== null) {\n\t\t\t\tfor (const [key, value] of Object.entries(acf)) {\n\t\t\t\t\tassignMetaValue(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.meta) {\n\t\t\t\tfor (const [key, value] of Object.entries(item.meta)) {\n\t\t\t\t\t// Underscore keys are WP-internal or handled above (_acf/_yoast/_rankmath)\n\t\t\t\t\tif (key.startsWith(\"_\")) continue;\n\t\t\t\t\tassignMetaValue(key, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Resolve author ID from mappings\n\t\t\tlet authorId: string | undefined;\n\t\t\tif (config.authorMappings && item.author) {\n\t\t\t\tconst mappedUserId = config.authorMappings[item.author];\n\t\t\t\tif (mappedUserId !== undefined && mappedUserId !== null) {\n\t\t\t\t\tauthorId = mappedUserId;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst bylineId = await resolveImportByline(\n\t\t\t\titem.author,\n\t\t\t\titem.author, // display name fallback is the login\n\t\t\t\tauthorId,\n\t\t\t\tbylineRepo,\n\t\t\t\tbylineCache,\n\t\t\t);\n\n\t\t\t// Resolve translation link: if this item has a translationGroup and\n\t\t\t// we've already imported another item in the same group, link them.\n\t\t\tlet translationOf: string | undefined;\n\t\t\tif (item.translationGroup) {\n\t\t\t\tconst existingGroupItem = translationGroupMap.get(item.translationGroup);\n\t\t\t\tif (existingGroupItem) {\n\t\t\t\t\ttranslationOf = existingGroupItem;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Preserve original dates from the source\n\t\t\tconst itemDateTime = item.date?.getTime();\n\t\t\tconst createdAt =\n\t\t\t\titemDateTime !== undefined && !Number.isNaN(itemDateTime)\n\t\t\t\t\t? item.date.toISOString()\n\t\t\t\t\t: undefined;\n\t\t\tconst publishedAt = status === \"published\" && createdAt ? createdAt : undefined;\n\n\t\t\t// Create the content item\n\t\t\tconst createResult = await emdash.handleContentCreate(collection, {\n\t\t\t\tdata,\n\t\t\t\tslug,\n\t\t\t\tstatus,\n\t\t\t\tauthorId,\n\t\t\t\tbylines: bylineId ? [{ bylineId }] : undefined,\n\t\t\t\tlocale: item.locale,\n\t\t\t\ttranslationOf,\n\t\t\t\tcreatedAt,\n\t\t\t\tpublishedAt,\n\t\t\t});\n\n\t\t\tif (createResult.success) {\n\t\t\t\tresult.imported++;\n\t\t\t\tresult.byCollection[collection] = (result.byCollection[collection] || 0) + 1;\n\n\t\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- create handler returns { item, _rev }\n\t\t\t\tconst createdData = createResult.data as { item?: { id?: string } } | undefined;\n\t\t\t\tconst createdId = createdData?.item?.id;\n\n\t\t\t\tif (createdId) {\n\t\t\t\t\tconst wpId = Number(item.sourceId);\n\t\t\t\t\tif (Number.isFinite(wpId)) {\n\t\t\t\t\t\tcontentIdMap.set(wpId, createdId);\n\t\t\t\t\t\tcollectionByWpId.set(wpId, collection);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Attach category/tag/custom-taxonomy assignments\n\t\t\t\t\tif (taxonomyPlan) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst attached = await attachPostTaxonomies(\n\t\t\t\t\t\t\t\temdash.db,\n\t\t\t\t\t\t\t\tcollection,\n\t\t\t\t\t\t\t\tcreatedId,\n\t\t\t\t\t\t\t\ttoWxrAssignments(item),\n\t\t\t\t\t\t\t\ttaxonomyPlan,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (attached > 0) {\n\t\t\t\t\t\t\t\tresult.taxonomyAssignments = (result.taxonomyAssignments ?? 0) + attached;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tconsole.warn(`[WP Plugin Import] Taxonomy attach failed for \"${slug}\":`, e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track translation group: first item in a group establishes the mapping\n\t\t\t\tif (item.translationGroup && !translationGroupMap.has(item.translationGroup) && createdId) {\n\t\t\t\t\ttranslationGroupMap.set(item.translationGroup, createdId);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult.errors.push({\n\t\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\t\terror:\n\t\t\t\t\t\ttypeof createResult.error === \"object\" && createResult.error !== null\n\t\t\t\t\t\t\t? (createResult.error as { message?: string }).message || \"Unknown error\"\n\t\t\t\t\t\t\t: String(createResult.error),\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(`Import error for \"${item.title || \"Untitled\"}\":`, error);\n\t\t\tresult.errors.push({\n\t\t\t\ttitle: item.title || \"Untitled\",\n\t\t\t\terror: error instanceof Error && error.message ? error.message : \"Failed to import item\",\n\t\t\t});\n\t\t}\n\t}\n\n\tif (taxonomyPlan && taxonomyPlan.missingTaxonomies.length > 0) {\n\t\tresult.missingTaxonomies = taxonomyPlan.missingTaxonomies;\n\t}\n\n\tresult.success = result.errors.length === 0;\n\treturn { result, contentIdMap, collectionByWpId };\n}\n\nfunction mapStatus(wpStatus: string | undefined): string {\n\tswitch (wpStatus) {\n\t\tcase \"publish\":\n\t\t\treturn \"published\";\n\t\tcase \"draft\":\n\t\t\treturn \"draft\";\n\t\tcase \"pending\":\n\t\t\treturn \"draft\";\n\t\tcase \"private\":\n\t\t\treturn \"draft\";\n\t\tdefault:\n\t\t\treturn \"draft\";\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../types-
|
|
2
|
+
import "../../../types-XrQQ-Aex.mjs";
|
|
3
3
|
import { t as OptionsRepository } from "../../../options-BlmBHTvX.mjs";
|
|
4
|
-
import { n as apiSuccess, r as handleError } from "../../../error-
|
|
5
|
-
import { n as VERSION, t as COMMIT } from "../../../version-
|
|
4
|
+
import { n as apiSuccess, r as handleError } from "../../../error-DmmN74gW.mjs";
|
|
5
|
+
import { n as VERSION, t as COMMIT } from "../../../version-Bdfb34kk.mjs";
|
|
6
6
|
import { t as getAuthMode } from "../../../mode-fiXRMfeA.mjs";
|
|
7
7
|
|
|
8
8
|
//#region src/astro/routes/api/manifest.ts
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import "../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../types-
|
|
3
|
-
import { t as apiError } from "../../../error-
|
|
4
|
-
import { t as CONTENT_TYPE_RE } from "../../../media-
|
|
5
|
-
import {
|
|
6
|
-
import "../../../relations-
|
|
2
|
+
import "../../../types-XrQQ-Aex.mjs";
|
|
3
|
+
import { t as apiError } from "../../../error-DmmN74gW.mjs";
|
|
4
|
+
import { t as CONTENT_TYPE_RE } from "../../../media-DWIzoVFL.mjs";
|
|
5
|
+
import { Qt as contentSeoInput, hn as contentBylineInputSchema, pn as bylineUpdateBody, sn as bylineCreateBody } from "../../../redirects-BOn2DIUs.mjs";
|
|
6
|
+
import "../../../relations-C4duJnwI.mjs";
|
|
7
7
|
import "../../../status-COfycGIU.mjs";
|
|
8
8
|
import "../../../api/schemas/index.mjs";
|
|
9
|
-
import { i as hasScope$1 } from "../../../api-tokens-
|
|
10
|
-
import { n as convertDataForWrite, t as convertDataForRead } from "../../../portable-text-
|
|
9
|
+
import { i as hasScope$1 } from "../../../api-tokens-CEsW_jCg.mjs";
|
|
10
|
+
import { n as convertDataForWrite, t as convertDataForRead } from "../../../portable-text-CNahFfj6.mjs";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { Permissions, Role, canActOnOwn, hasPermission } from "@emdash-cms/auth";
|
|
13
13
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
@@ -173,7 +173,7 @@ function getEmDash(extra) {
|
|
|
173
173
|
}
|
|
174
174
|
async function getCollectionFields(ec, collection) {
|
|
175
175
|
try {
|
|
176
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
176
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
177
177
|
const col = await new SchemaRegistry(ec.db).getCollectionWithFields(collection);
|
|
178
178
|
return col ? col.fields : null;
|
|
179
179
|
} catch {
|
|
@@ -202,7 +202,7 @@ async function applyReadMarkdown(ec, collection, items) {
|
|
|
202
202
|
for (const item of items) if (item.data && typeof item.data === "object") item.data = convertDataForRead(item.data, fields, false);
|
|
203
203
|
}
|
|
204
204
|
async function invalidateBylines() {
|
|
205
|
-
const { invalidateBylineCache } = await import("../../../bylines-
|
|
205
|
+
const { invalidateBylineCache } = await import("../../../bylines-B8-WGdja.mjs").then((n) => n.t);
|
|
206
206
|
invalidateBylineCache();
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
@@ -758,7 +758,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
758
758
|
requireScope(extra, "content:read");
|
|
759
759
|
const ec = getEmDash(extra);
|
|
760
760
|
try {
|
|
761
|
-
const { BylineRepository } = await import("../../../byline-
|
|
761
|
+
const { BylineRepository } = await import("../../../byline-C5TAqs8N.mjs").then((n) => n.n);
|
|
762
762
|
return jsonResult(await new BylineRepository(ec.db).findMany({
|
|
763
763
|
search: args.search,
|
|
764
764
|
isGuest: args.isGuest,
|
|
@@ -780,7 +780,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
780
780
|
requireScope(extra, "content:read");
|
|
781
781
|
const ec = getEmDash(extra);
|
|
782
782
|
try {
|
|
783
|
-
const { BylineRepository } = await import("../../../byline-
|
|
783
|
+
const { BylineRepository } = await import("../../../byline-C5TAqs8N.mjs").then((n) => n.n);
|
|
784
784
|
const byline = await new BylineRepository(ec.db).findById(args.id);
|
|
785
785
|
if (!byline) return respondError("NOT_FOUND", `Byline '${args.id}' not found`);
|
|
786
786
|
return jsonResult(byline);
|
|
@@ -798,7 +798,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
798
798
|
requireRole(extra, Role.EDITOR);
|
|
799
799
|
const ec = getEmDash(extra);
|
|
800
800
|
try {
|
|
801
|
-
const { handleBylineCreate } = await import("../../../bylines-
|
|
801
|
+
const { handleBylineCreate } = await import("../../../bylines-DGuqBLjV.mjs").then((n) => n.t);
|
|
802
802
|
const result = await handleBylineCreate(ec.db, args);
|
|
803
803
|
if (result.success) await invalidateBylines();
|
|
804
804
|
return unwrap(result);
|
|
@@ -818,7 +818,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
818
818
|
requireRole(extra, Role.EDITOR);
|
|
819
819
|
const ec = getEmDash(extra);
|
|
820
820
|
try {
|
|
821
|
-
const { handleBylineUpdate } = await import("../../../bylines-
|
|
821
|
+
const { handleBylineUpdate } = await import("../../../bylines-DGuqBLjV.mjs").then((n) => n.t);
|
|
822
822
|
const { id, ...input } = args;
|
|
823
823
|
const result = await handleBylineUpdate(ec.db, id, input);
|
|
824
824
|
if (result.success) await invalidateBylines();
|
|
@@ -837,7 +837,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
837
837
|
requireRole(extra, Role.EDITOR);
|
|
838
838
|
const ec = getEmDash(extra);
|
|
839
839
|
try {
|
|
840
|
-
const { BylineRepository } = await import("../../../byline-
|
|
840
|
+
const { BylineRepository } = await import("../../../byline-C5TAqs8N.mjs").then((n) => n.n);
|
|
841
841
|
if (!await new BylineRepository(ec.db).delete(args.id)) return respondError("NOT_FOUND", `Byline '${args.id}' not found`);
|
|
842
842
|
await invalidateBylines();
|
|
843
843
|
return jsonResult({ deleted: args.id });
|
|
@@ -854,7 +854,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
854
854
|
requireScope(extra, "content:read");
|
|
855
855
|
const ec = getEmDash(extra);
|
|
856
856
|
try {
|
|
857
|
-
const { handleBylineTranslations } = await import("../../../bylines-
|
|
857
|
+
const { handleBylineTranslations } = await import("../../../bylines-DGuqBLjV.mjs").then((n) => n.t);
|
|
858
858
|
return unwrap(await handleBylineTranslations(ec.db, args.id));
|
|
859
859
|
} catch (error) {
|
|
860
860
|
return respondHandlerError(error, "BYLINE_TRANSLATIONS_ERROR");
|
|
@@ -870,7 +870,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
870
870
|
requireRole(extra, Role.EDITOR);
|
|
871
871
|
const ec = getEmDash(extra);
|
|
872
872
|
try {
|
|
873
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
873
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
874
874
|
return jsonResult({ items: await new SchemaRegistry(ec.db).listCollections() });
|
|
875
875
|
} catch (error) {
|
|
876
876
|
return respondHandlerError(error, "SCHEMA_LIST_ERROR");
|
|
@@ -886,7 +886,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
886
886
|
requireRole(extra, Role.EDITOR);
|
|
887
887
|
const ec = getEmDash(extra);
|
|
888
888
|
try {
|
|
889
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
889
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
890
890
|
const collection = await new SchemaRegistry(ec.db).getCollectionWithFields(args.slug);
|
|
891
891
|
if (!collection) return respondError("NOT_FOUND", `Collection '${args.slug}' not found`);
|
|
892
892
|
return jsonResult(collection);
|
|
@@ -916,7 +916,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
916
916
|
requireRole(extra, Role.ADMIN);
|
|
917
917
|
const ec = getEmDash(extra);
|
|
918
918
|
try {
|
|
919
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
919
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
920
920
|
const collection = await new SchemaRegistry(ec.db).createCollection({
|
|
921
921
|
slug: args.slug,
|
|
922
922
|
label: args.label,
|
|
@@ -944,7 +944,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
944
944
|
requireRole(extra, Role.ADMIN);
|
|
945
945
|
const ec = getEmDash(extra);
|
|
946
946
|
try {
|
|
947
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
947
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
948
948
|
await new SchemaRegistry(ec.db).deleteCollection(args.slug, { force: args.force });
|
|
949
949
|
ec.invalidateUrlPatternCache();
|
|
950
950
|
return jsonResult({ deleted: args.slug });
|
|
@@ -998,7 +998,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
998
998
|
requireRole(extra, Role.ADMIN);
|
|
999
999
|
const ec = getEmDash(extra);
|
|
1000
1000
|
try {
|
|
1001
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
1001
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
1002
1002
|
return jsonResult(await new SchemaRegistry(ec.db).createField(args.collection, {
|
|
1003
1003
|
slug: args.slug,
|
|
1004
1004
|
label: args.label,
|
|
@@ -1028,7 +1028,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1028
1028
|
requireRole(extra, Role.ADMIN);
|
|
1029
1029
|
const ec = getEmDash(extra);
|
|
1030
1030
|
try {
|
|
1031
|
-
const { SchemaRegistry } = await import("../../../schema-
|
|
1031
|
+
const { SchemaRegistry } = await import("../../../schema-eqZhkR0S.mjs").then((n) => n.t);
|
|
1032
1032
|
await new SchemaRegistry(ec.db).deleteField(args.collection, args.fieldSlug);
|
|
1033
1033
|
return jsonResult({
|
|
1034
1034
|
deleted: args.fieldSlug,
|
|
@@ -1103,7 +1103,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1103
1103
|
const { emdash, userId } = getExtra(extra);
|
|
1104
1104
|
if (!emdash.storage) return respondError("NO_STORAGE", "Storage not configured");
|
|
1105
1105
|
try {
|
|
1106
|
-
const { handleMediaUpload } = await import("../../../media-upload-
|
|
1106
|
+
const { handleMediaUpload } = await import("../../../media-upload-Bc9Nc5Zf.mjs");
|
|
1107
1107
|
return unwrap(await handleMediaUpload(emdash.db, emdash.storage, {
|
|
1108
1108
|
filename: args.filename,
|
|
1109
1109
|
base64: args.base64,
|
|
@@ -1183,7 +1183,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1183
1183
|
};
|
|
1184
1184
|
} else input = { scope: "all" };
|
|
1185
1185
|
try {
|
|
1186
|
-
const { handleMediaUsageRepair } = await import("../../../media-usage-
|
|
1186
|
+
const { handleMediaUsageRepair } = await import("../../../media-usage-DPJcNaAq.mjs").then((n) => n.i);
|
|
1187
1187
|
return unwrap(await handleMediaUsageRepair(ec.db, input));
|
|
1188
1188
|
} catch (error) {
|
|
1189
1189
|
return respondHandlerError(error, "MEDIA_USAGE_REPAIR_ERROR");
|
|
@@ -1204,7 +1204,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1204
1204
|
requireScope(extra, "content:read");
|
|
1205
1205
|
const ec = getEmDash(extra);
|
|
1206
1206
|
try {
|
|
1207
|
-
const { searchWithDb } = await import("../../../search-
|
|
1207
|
+
const { searchWithDb } = await import("../../../search-CeO678cp.mjs").then((n) => n.t);
|
|
1208
1208
|
return jsonResult(await searchWithDb(ec.db, args.query, {
|
|
1209
1209
|
collections: args.collections,
|
|
1210
1210
|
locale: args.locale,
|
|
@@ -1224,7 +1224,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1224
1224
|
requireScope(extra, "content:read");
|
|
1225
1225
|
const ec = getEmDash(extra);
|
|
1226
1226
|
try {
|
|
1227
|
-
const { handleTaxonomyList } = await import("../../../taxonomies-
|
|
1227
|
+
const { handleTaxonomyList } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1228
1228
|
return unwrap(await handleTaxonomyList(ec.db, { locale: args.locale }));
|
|
1229
1229
|
} catch (error) {
|
|
1230
1230
|
return respondHandlerError(error, "TAXONOMY_LIST_ERROR");
|
|
@@ -1244,12 +1244,12 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1244
1244
|
requireScope(extra, "content:read");
|
|
1245
1245
|
const ec = getEmDash(extra);
|
|
1246
1246
|
try {
|
|
1247
|
-
const { handleTaxonomyList } = await import("../../../taxonomies-
|
|
1247
|
+
const { handleTaxonomyList } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1248
1248
|
const listResult = await handleTaxonomyList(ec.db, { locale: args.locale });
|
|
1249
1249
|
if (!listResult.success) return unwrap(listResult);
|
|
1250
1250
|
if (!listResult.data.taxonomies.find((t) => t.name === args.taxonomy)) return respondError("NOT_FOUND", `Taxonomy '${args.taxonomy}' not found`);
|
|
1251
|
-
const { TaxonomyRepository } = await import("../../../taxonomy-
|
|
1252
|
-
const { decodeCursor, encodeCursor, InvalidCursorError } = await import("../../../types-
|
|
1251
|
+
const { TaxonomyRepository } = await import("../../../taxonomy-DvwWAPvA.mjs").then((n) => n.n);
|
|
1252
|
+
const { decodeCursor, encodeCursor, InvalidCursorError } = await import("../../../types-XrQQ-Aex.mjs").then((n) => n.o);
|
|
1253
1253
|
const repo = new TaxonomyRepository(ec.db);
|
|
1254
1254
|
const limit = Math.min(args.limit ?? 50, 100);
|
|
1255
1255
|
const terms = await repo.findByName(args.taxonomy, { locale: args.locale });
|
|
@@ -1303,7 +1303,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1303
1303
|
requireRole(extra, Role.EDITOR);
|
|
1304
1304
|
const ec = getEmDash(extra);
|
|
1305
1305
|
try {
|
|
1306
|
-
const { handleTermCreate } = await import("../../../taxonomies-
|
|
1306
|
+
const { handleTermCreate } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1307
1307
|
return unwrap(await handleTermCreate(ec.db, args.taxonomy, {
|
|
1308
1308
|
slug: args.slug,
|
|
1309
1309
|
label: args.label,
|
|
@@ -1332,7 +1332,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1332
1332
|
requireRole(extra, Role.EDITOR);
|
|
1333
1333
|
const ec = getEmDash(extra);
|
|
1334
1334
|
try {
|
|
1335
|
-
const { handleTermUpdate } = await import("../../../taxonomies-
|
|
1335
|
+
const { handleTermUpdate } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1336
1336
|
return unwrap(await handleTermUpdate(ec.db, args.taxonomy, args.termSlug, {
|
|
1337
1337
|
slug: args.slug,
|
|
1338
1338
|
label: args.label,
|
|
@@ -1356,7 +1356,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1356
1356
|
requireRole(extra, Role.EDITOR);
|
|
1357
1357
|
const ec = getEmDash(extra);
|
|
1358
1358
|
try {
|
|
1359
|
-
const { handleTermDelete } = await import("../../../taxonomies-
|
|
1359
|
+
const { handleTermDelete } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1360
1360
|
return unwrap(await handleTermDelete(ec.db, args.taxonomy, args.termSlug));
|
|
1361
1361
|
} catch (error) {
|
|
1362
1362
|
return respondHandlerError(error, "TAXONOMY_TERM_DELETE_ERROR");
|
|
@@ -1371,7 +1371,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1371
1371
|
requireScope(extra, "content:read");
|
|
1372
1372
|
const ec = getEmDash(extra);
|
|
1373
1373
|
try {
|
|
1374
|
-
const { handleTermTranslations } = await import("../../../taxonomies-
|
|
1374
|
+
const { handleTermTranslations } = await import("../../../taxonomies-Dbdki3Un.mjs").then((n) => n.l);
|
|
1375
1375
|
return unwrap(await handleTermTranslations(ec.db, args.id));
|
|
1376
1376
|
} catch (error) {
|
|
1377
1377
|
return respondHandlerError(error, "TERM_TRANSLATIONS_ERROR");
|
|
@@ -1386,7 +1386,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1386
1386
|
requireScope(extra, "content:read");
|
|
1387
1387
|
const ec = getEmDash(extra);
|
|
1388
1388
|
try {
|
|
1389
|
-
const { handleMenuList } = await import("../../../menus-
|
|
1389
|
+
const { handleMenuList } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1390
1390
|
return unwrap(await handleMenuList(ec.db, { locale: args.locale }));
|
|
1391
1391
|
} catch (error) {
|
|
1392
1392
|
return respondHandlerError(error, "MENU_LIST_ERROR");
|
|
@@ -1404,7 +1404,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1404
1404
|
requireScope(extra, "content:read");
|
|
1405
1405
|
const ec = getEmDash(extra);
|
|
1406
1406
|
try {
|
|
1407
|
-
const { handleMenuGet } = await import("../../../menus-
|
|
1407
|
+
const { handleMenuGet } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1408
1408
|
return unwrap(await handleMenuGet(ec.db, args.name, { locale: args.locale }));
|
|
1409
1409
|
} catch (error) {
|
|
1410
1410
|
return respondHandlerError(error, "MENU_GET_ERROR");
|
|
@@ -1419,7 +1419,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1419
1419
|
requireScope(extra, "content:read");
|
|
1420
1420
|
const ec = getEmDash(extra);
|
|
1421
1421
|
try {
|
|
1422
|
-
const { handleMenuTranslations } = await import("../../../menus-
|
|
1422
|
+
const { handleMenuTranslations } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1423
1423
|
return unwrap(await handleMenuTranslations(ec.db, args.id));
|
|
1424
1424
|
} catch (error) {
|
|
1425
1425
|
return respondHandlerError(error, "MENU_TRANSLATIONS_ERROR");
|
|
@@ -1439,7 +1439,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1439
1439
|
requireRole(extra, Role.EDITOR);
|
|
1440
1440
|
const ec = getEmDash(extra);
|
|
1441
1441
|
try {
|
|
1442
|
-
const { handleMenuCreate } = await import("../../../menus-
|
|
1442
|
+
const { handleMenuCreate } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1443
1443
|
return unwrap(await handleMenuCreate(ec.db, {
|
|
1444
1444
|
name: args.name,
|
|
1445
1445
|
label: args.label,
|
|
@@ -1463,7 +1463,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1463
1463
|
requireRole(extra, Role.EDITOR);
|
|
1464
1464
|
const ec = getEmDash(extra);
|
|
1465
1465
|
try {
|
|
1466
|
-
const { handleMenuUpdate } = await import("../../../menus-
|
|
1466
|
+
const { handleMenuUpdate } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1467
1467
|
return unwrap(await handleMenuUpdate(ec.db, args.name, {
|
|
1468
1468
|
label: args.label,
|
|
1469
1469
|
locale: args.locale
|
|
@@ -1485,7 +1485,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1485
1485
|
requireRole(extra, Role.EDITOR);
|
|
1486
1486
|
const ec = getEmDash(extra);
|
|
1487
1487
|
try {
|
|
1488
|
-
const { handleMenuDelete } = await import("../../../menus-
|
|
1488
|
+
const { handleMenuDelete } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1489
1489
|
return unwrap(await handleMenuDelete(ec.db, args.name, { locale: args.locale }));
|
|
1490
1490
|
} catch (error) {
|
|
1491
1491
|
return respondHandlerError(error, "MENU_DELETE_ERROR");
|
|
@@ -1520,7 +1520,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1520
1520
|
requireRole(extra, Role.EDITOR);
|
|
1521
1521
|
const ec = getEmDash(extra);
|
|
1522
1522
|
try {
|
|
1523
|
-
const { handleMenuSetItems } = await import("../../../menus-
|
|
1523
|
+
const { handleMenuSetItems } = await import("../../../menus-BxPLFfIc.mjs").then((n) => n.d);
|
|
1524
1524
|
return unwrap(await handleMenuSetItems(ec.db, args.name, args.items, { locale: args.locale }));
|
|
1525
1525
|
} catch (error) {
|
|
1526
1526
|
return respondHandlerError(error, "MENU_SET_ITEMS_ERROR");
|
|
@@ -1567,7 +1567,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1567
1567
|
requireRole(extra, Role.EDITOR);
|
|
1568
1568
|
const ec = getEmDash(extra);
|
|
1569
1569
|
try {
|
|
1570
|
-
const { handleSettingsGet } = await import("../../../settings-
|
|
1570
|
+
const { handleSettingsGet } = await import("../../../settings-CREKyj8I.mjs").then((n) => n.r);
|
|
1571
1571
|
return unwrap(await handleSettingsGet(ec.db, ec.storage));
|
|
1572
1572
|
} catch (error) {
|
|
1573
1573
|
return respondHandlerError(error, "SETTINGS_READ_ERROR");
|
|
@@ -1593,7 +1593,7 @@ function createMcpServer(pluginTools = [], request) {
|
|
|
1593
1593
|
requireRole(extra, Role.ADMIN);
|
|
1594
1594
|
const ec = getEmDash(extra);
|
|
1595
1595
|
try {
|
|
1596
|
-
const { handleSettingsUpdate } = await import("../../../settings-
|
|
1596
|
+
const { handleSettingsUpdate } = await import("../../../settings-CREKyj8I.mjs").then((n) => n.r);
|
|
1597
1597
|
return unwrap(await handleSettingsUpdate(ec.db, ec.storage, args));
|
|
1598
1598
|
} catch (error) {
|
|
1599
1599
|
return respondHandlerError(error, "SETTINGS_UPDATE_ERROR");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm.d.mts","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"confirm.d.mts","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"mappings":";;;cAqBa,SAAA;;;;cAqFA,IAAA,EAAM,QAAA"}
|