emdash 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-DAAjOID4.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
- package/dist/{adapters-DAAjOID4.d.mts.map → adapters-hUy8vOB-.d.mts.map} +1 -1
- package/dist/{allowed-origins-D5FxMUo8.mjs → allowed-origins-CRsJ6BPM.mjs} +2 -2
- package/dist/{allowed-origins-D5FxMUo8.mjs.map → allowed-origins-CRsJ6BPM.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +17 -16
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-BMfveMoB.mjs → api-BFURZn1i.mjs} +104 -38
- package/dist/api-BFURZn1i.mjs.map +1 -0
- package/dist/{api-tokens-D6ppjIVi.mjs → api-tokens-DvqeZmVq.mjs} +2 -2
- package/dist/{api-tokens-D6ppjIVi.mjs.map → api-tokens-DvqeZmVq.mjs.map} +1 -1
- package/dist/{apply--IVNSdXn.mjs → apply-Bu-8nYHL.mjs} +113 -76
- package/dist/apply-Bu-8nYHL.mjs.map +1 -0
- package/dist/astro/index.d.mts +12 -11
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +13 -5
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -9
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +52 -12
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +2 -2
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +2 -9
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +125 -71
- 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 +14 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
- package/dist/astro/routes/api/admin/bylines/index.mjs +14 -14
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
- package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- 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/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 +38 -37
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +38 -37
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +37 -36
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +36 -35
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +36 -35
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +37 -36
- 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 -35
- 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 -35
- 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 -35
- 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 -35
- 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 -36
- 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 -35
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +37 -36
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +36 -35
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +36 -35
- 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 -35
- 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 +5 -5
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
- package/dist/astro/routes/api/auth/logout.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
- 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 +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
- 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 +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
- 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 +13 -13
- 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_.mjs +7 -7
- 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 +8 -8
- package/dist/astro/routes/api/dev/emails.mjs +3 -3
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +19 -11
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -40
- package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -407
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -9
- package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +19 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +97 -79
- 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 +19 -11
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +40 -2
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +519 -39
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.d.mts.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +14 -5
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +39 -39
- package/dist/astro/routes/api/media/_id_/confirm.mjs +7 -7
- package/dist/astro/routes/api/media/_id_.mjs +7 -7
- 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.mjs +8 -8
- package/dist/astro/routes/api/media.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_.mjs +9 -9
- package/dist/astro/routes/api/menus/index.mjs +9 -9
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- 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 +4 -4
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
- package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
- package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
- package/dist/astro/routes/api/redirects/index.mjs +10 -10
- 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 -35
- 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 -35
- 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 -35
- 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 -35
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +36 -35
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +7 -6
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +36 -35
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +36 -35
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +10 -10
- package/dist/astro/routes/api/search/index.mjs +9 -9
- package/dist/astro/routes/api/search/rebuild.mjs +10 -10
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +9 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
- package/dist/astro/routes/api/sections/index.mjs +9 -9
- 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 +11 -11
- package/dist/astro/routes/api/setup/admin.mjs +10 -10
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +28 -25
- 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 +26 -25
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +4 -4
- package/dist/astro/routes/api/snapshot.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +9 -9
- package/dist/astro/routes/api/widget-components.mjs +3 -3
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +14 -12
- 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-BZnOGJFo.mjs → authorize-Dz88F_Fw.mjs} +2 -2
- package/dist/{authorize-BZnOGJFo.mjs.map → authorize-Dz88F_Fw.mjs.map} +1 -1
- package/dist/{byline-LL8lyqdb.mjs → byline-Bm8ZgUP9.mjs} +6 -6
- package/dist/{byline-LL8lyqdb.mjs.map → byline-Bm8ZgUP9.mjs.map} +1 -1
- package/dist/{byline-fields-eyJMblSr.mjs → byline-fields-2Lp5Hbgf.mjs} +18 -3
- package/dist/byline-fields-2Lp5Hbgf.mjs.map +1 -0
- package/dist/{byline-fields-DaMKzkhO.mjs → byline-fields-CIx_GuN4.mjs} +1 -1
- package/dist/{byline-fields-DaMKzkhO.mjs.map → byline-fields-CIx_GuN4.mjs.map} +1 -1
- package/dist/{byline-fields-KD3JFRuH.d.mts → byline-fields-Cgrt9-aL.d.mts} +18 -3
- package/dist/{byline-fields-KD3JFRuH.d.mts.map → byline-fields-Cgrt9-aL.d.mts.map} +1 -1
- package/dist/{bylines-BmJ7Vg7J.mjs → bylines-6tm9mgQb.mjs} +4 -4
- package/dist/{bylines-BmJ7Vg7J.mjs.map → bylines-6tm9mgQb.mjs.map} +1 -1
- package/dist/{bylines-DE47vP8d.mjs → bylines-Woq87129.mjs} +6 -6
- package/dist/{bylines-DE47vP8d.mjs.map → bylines-Woq87129.mjs.map} +1 -1
- package/dist/{cache-D9jF5bYw.mjs → cache-CEBAZjir.mjs} +2 -2
- package/dist/{cache-D9jF5bYw.mjs.map → cache-CEBAZjir.mjs.map} +1 -1
- package/dist/{challenge-store-LhiqMccz.mjs → challenge-store-anhwVER0.mjs} +1 -1
- package/dist/{challenge-store-LhiqMccz.mjs.map → challenge-store-anhwVER0.mjs.map} +1 -1
- package/dist/{chunks-OCG163rN.mjs → chunks-B2isWQhr.mjs} +2 -2
- package/dist/{chunks-OCG163rN.mjs.map → chunks-B2isWQhr.mjs.map} +1 -1
- package/dist/cli/index.mjs +23 -22
- 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-D9BLDpZI.mjs → comment-CzeatwBV.mjs} +3 -3
- package/dist/{comment-D9BLDpZI.mjs.map → comment-CzeatwBV.mjs.map} +1 -1
- package/dist/{comment-reaction-Drl9SkNu.mjs → comment-reaction-Cj9QJY7I.mjs} +2 -2
- package/dist/{comment-reaction-Drl9SkNu.mjs.map → comment-reaction-Cj9QJY7I.mjs.map} +1 -1
- package/dist/{comments-BjJ9SKGU.mjs → comments-BLE-jv5k.mjs} +3 -3
- package/dist/{comments-BjJ9SKGU.mjs.map → comments-BLE-jv5k.mjs.map} +1 -1
- package/dist/{components-CYt4uVK9.mjs → components-B_sATNUc.mjs} +1 -1
- package/dist/{components-CYt4uVK9.mjs.map → components-B_sATNUc.mjs.map} +1 -1
- package/dist/{content-ncUWWjna.mjs → content-DhgEth4k.mjs} +4 -4
- package/dist/{content-ncUWWjna.mjs.map → content-DhgEth4k.mjs.map} +1 -1
- package/dist/content-refresh-CA4uKwzH.mjs +1531 -0
- package/dist/content-refresh-CA4uKwzH.mjs.map +1 -0
- package/dist/{context-C_g-iJVA.mjs → context-CUsR9dXL.mjs} +76 -54
- package/dist/context-CUsR9dXL.mjs.map +1 -0
- package/dist/{cron-C5LVoNmP.mjs → cron-v4FTEFR_.mjs} +1 -1
- package/dist/{cron-C5LVoNmP.mjs.map → cron-v4FTEFR_.mjs.map} +1 -1
- package/dist/{dashboard-CotyqQrW.mjs → dashboard-EvEKF5en.mjs} +4 -4
- package/dist/{dashboard-CotyqQrW.mjs.map → dashboard-EvEKF5en.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{default-CeRG-Ot4.mjs → default-CM_D83Mg.mjs} +1 -1
- package/dist/{default-CeRG-Ot4.mjs.map → default-CM_D83Mg.mjs.map} +1 -1
- package/dist/{device-flow-DENDCQ9F.mjs → device-flow-CfGP18Uw.mjs} +4 -4
- package/dist/{device-flow-DENDCQ9F.mjs.map → device-flow-CfGP18Uw.mjs.map} +1 -1
- package/dist/{email-console-DJP32ucW.mjs → email-console-CIf4Lfvv.mjs} +1 -1
- package/dist/{email-console-DJP32ucW.mjs.map → email-console-CIf4Lfvv.mjs.map} +1 -1
- package/dist/{error-rVGiqWDt.mjs → error-CkAseSqZ.mjs} +2 -2
- package/dist/{error-rVGiqWDt.mjs.map → error-CkAseSqZ.mjs.map} +1 -1
- package/dist/{escape-Bjio4ZsM.mjs → escape-DqD0aCKu.mjs} +1 -1
- package/dist/{escape-Bjio4ZsM.mjs.map → escape-DqD0aCKu.mjs.map} +1 -1
- package/dist/{field-defs-cache-ljXzJCfc.mjs → field-defs-cache-WUI88LX5.mjs} +2 -2
- package/dist/{field-defs-cache-ljXzJCfc.mjs.map → field-defs-cache-WUI88LX5.mjs.map} +1 -1
- package/dist/{fts-manager-BbCCbEKA.mjs → fts-manager-BbFaF_V8.mjs} +2 -2
- package/dist/{fts-manager-BbCCbEKA.mjs.map → fts-manager-BbFaF_V8.mjs.map} +1 -1
- package/dist/{import-Bb1T9WJS.mjs → import-fYLf14Co.mjs} +514 -25
- package/dist/import-fYLf14Co.mjs.map +1 -0
- package/dist/{index-BRNabKrx.d.mts → index-B9sIxwe4.d.mts} +2420 -2379
- package/dist/index-B9sIxwe4.d.mts.map +1 -0
- package/dist/{index-Dt0OKJB4.d.mts → index-Bm-Gy8Mh.d.mts} +25 -4
- package/dist/index-Bm-Gy8Mh.d.mts.map +1 -0
- package/dist/index.d.mts +18 -17
- package/dist/index.mjs +54 -53
- package/dist/{load-DMjXghbZ.mjs → load-Djn3HWQS.mjs} +2 -2
- package/dist/{load-DMjXghbZ.mjs.map → load-Djn3HWQS.mjs.map} +1 -1
- package/dist/{loader-BA_zhkS_.mjs → loader-CB6YHeul.mjs} +6 -5
- package/dist/loader-CB6YHeul.mjs.map +1 -0
- package/dist/{manifest-schema-kPGX7VS-.mjs → manifest-schema-BHlgZM1W.mjs} +1 -1
- package/dist/{manifest-schema-kPGX7VS-.mjs.map → manifest-schema-BHlgZM1W.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/local-runtime.d.mts +12 -11
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-C5t_eCnk.mjs → media-BrXIaMFN.mjs} +2 -2
- package/dist/{media-C5t_eCnk.mjs.map → media-BrXIaMFN.mjs.map} +1 -1
- package/dist/{media-allowlist-Du8t1u6a.mjs → media-allowlist-CRHEeJ_i.mjs} +1 -1
- package/dist/{media-allowlist-Du8t1u6a.mjs.map → media-allowlist-CRHEeJ_i.mjs.map} +1 -1
- package/dist/{media-url-O4rm9-SQ.mjs → media-url-CKi5XSw4.mjs} +1 -1
- package/dist/{media-url-O4rm9-SQ.mjs.map → media-url-CKi5XSw4.mjs.map} +1 -1
- package/dist/{menus-CBb6UrMU.mjs → menus-Cfivc2Ad.mjs} +3 -3
- package/dist/{menus-CBb6UrMU.mjs.map → menus-Cfivc2Ad.mjs.map} +1 -1
- package/dist/{menus-CYH09a41.mjs → menus-CsZ2ZEK2.mjs} +16 -12
- package/dist/{menus-CYH09a41.mjs.map → menus-CsZ2ZEK2.mjs.map} +1 -1
- package/dist/{mode-BB0F8xTC.mjs → mode-BM9QgEmt.mjs} +1 -1
- package/dist/{mode-BB0F8xTC.mjs.map → mode-BM9QgEmt.mjs.map} +1 -1
- package/dist/{oauth-authorization-CsvzIp_F.mjs → oauth-authorization-CXWkIGT4.mjs} +4 -4
- package/dist/{oauth-authorization-CsvzIp_F.mjs.map → oauth-authorization-CXWkIGT4.mjs.map} +1 -1
- package/dist/{oauth-clients-C9SYwEbZ.mjs → oauth-clients-BmTI5rsl.mjs} +1 -1
- package/dist/{oauth-clients-C9SYwEbZ.mjs.map → oauth-clients-BmTI5rsl.mjs.map} +1 -1
- package/dist/{oauth-state-store---zrApfB.mjs → oauth-state-store-YLFLcH5F.mjs} +1 -1
- package/dist/{oauth-state-store---zrApfB.mjs.map → oauth-state-store-YLFLcH5F.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-SHsWRlG9.mjs → oauth-user-lookup-Bsc_GsX-.mjs} +1 -1
- package/dist/{oauth-user-lookup-SHsWRlG9.mjs.map → oauth-user-lookup-Bsc_GsX-.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-CHbHv83-.mjs → object-cache-Bok5j2ae.mjs} +43 -3
- package/dist/object-cache-Bok5j2ae.mjs.map +1 -0
- package/dist/{options-41nCWqi9.d.mts → options-iMpRRxIe.d.mts} +3 -3
- package/dist/{options-41nCWqi9.d.mts.map → options-iMpRRxIe.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-BwAdS7FZ.mjs → parse-GmjecGct.mjs} +2 -2
- package/dist/{parse-BwAdS7FZ.mjs.map → parse-GmjecGct.mjs.map} +1 -1
- package/dist/{passkey-config-C0YfSBko.mjs → passkey-config-De0ahnRg.mjs} +1 -1
- package/dist/{passkey-config-C0YfSBko.mjs.map → passkey-config-De0ahnRg.mjs.map} +1 -1
- package/dist/{placeholder-Cuce9U-m.d.mts → placeholder-BSKwzRe4.d.mts} +1 -1
- package/dist/{placeholder-Cuce9U-m.d.mts.map → placeholder-BSKwzRe4.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +10 -9
- package/dist/plugin-utils.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{portable-text-BICg8bTk.mjs → portable-text-cCa0cGV6.mjs} +1 -1
- package/dist/{portable-text-BICg8bTk.mjs.map → portable-text-cCa0cGV6.mjs.map} +1 -1
- package/dist/{preview-DKGCt2_p.mjs → preview-SSXNVPAC.mjs} +2 -2
- package/dist/{preview-DKGCt2_p.mjs.map → preview-SSXNVPAC.mjs.map} +1 -1
- package/dist/{public-url-CTVqgMmg.mjs → public-url-Danv47cS.mjs} +1 -1
- package/dist/{public-url-CTVqgMmg.mjs.map → public-url-Danv47cS.mjs.map} +1 -1
- package/dist/{query-BpQb-blG.mjs → query-ByGq6ver.mjs} +14 -14
- package/dist/{query-BpQb-blG.mjs.map → query-ByGq6ver.mjs.map} +1 -1
- package/dist/{rate-limit-Dap6HMNM.mjs → rate-limit-C_Lf63Dd.mjs} +2 -2
- package/dist/{rate-limit-Dap6HMNM.mjs.map → rate-limit-C_Lf63Dd.mjs.map} +1 -1
- package/dist/{redirect-CS-PHtNh.mjs → redirect-CoW3G-0U.mjs} +1 -1
- package/dist/{redirect-CS-PHtNh.mjs.map → redirect-CoW3G-0U.mjs.map} +1 -1
- package/dist/{redirect-_M0trWoo.mjs → redirect-IyfNirgS.mjs} +2 -2
- package/dist/{redirect-_M0trWoo.mjs.map → redirect-IyfNirgS.mjs.map} +1 -1
- package/dist/{redirects-w0V9vj_j.mjs → redirects-Bs1g42Ri.mjs} +4 -4
- package/dist/{redirects-w0V9vj_j.mjs.map → redirects-Bs1g42Ri.mjs.map} +1 -1
- package/dist/{redirects-Dcbuisoj.mjs → redirects-DXEXBAII.mjs} +2 -2
- package/dist/{redirects-Dcbuisoj.mjs.map → redirects-DXEXBAII.mjs.map} +1 -1
- package/dist/{registry-g8yYt4cC.mjs → registry-B65mUtPa.mjs} +122 -79
- package/dist/registry-B65mUtPa.mjs.map +1 -0
- package/dist/{request-meta-CmS1tDFf.mjs → request-meta-DbvXaAvU.mjs} +2 -2
- package/dist/{request-meta-CmS1tDFf.mjs.map → request-meta-DbvXaAvU.mjs.map} +1 -1
- package/dist/{resolve-C7I0qiR0.mjs → resolve-DR3wqMTy.mjs} +1 -1
- package/dist/{resolve-C7I0qiR0.mjs.map → resolve-DR3wqMTy.mjs.map} +1 -1
- package/dist/{runner-BbR3DfrL.d.mts → runner-DvFWoz8-.d.mts} +2 -2
- package/dist/{runner-BbR3DfrL.d.mts.map → runner-DvFWoz8-.d.mts.map} +1 -1
- package/dist/{runner-DPdt_Wpa.mjs → runner-K8XK101B.mjs} +351 -199
- package/dist/runner-K8XK101B.mjs.map +1 -0
- package/dist/runtime.d.mts +11 -10
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/scheduled-publish-Drffrf2a.d.mts +11 -0
- package/dist/scheduled-publish-Drffrf2a.d.mts.map +1 -0
- package/dist/{schema-DoLd3j2e.mjs → schema-Blhoxp3P.mjs} +5 -5
- package/dist/{schema-DoLd3j2e.mjs.map → schema-Blhoxp3P.mjs.map} +1 -1
- package/dist/{search-BR0ZeZmh.mjs → search-DZN2HZ-V.mjs} +6 -4
- package/dist/search-DZN2HZ-V.mjs.map +1 -0
- package/dist/{secrets-BSf9pRRY.mjs → secrets-kp760LlD.mjs} +2 -2
- package/dist/{secrets-BSf9pRRY.mjs.map → secrets-kp760LlD.mjs.map} +1 -1
- package/dist/{sections-5J2YJPqJ.mjs → sections-CpF5SaGr.mjs} +3 -3
- package/dist/{sections-5J2YJPqJ.mjs.map → sections-CpF5SaGr.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +19 -18
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-BkhuuaaE.mjs → seo-89-53DDs.mjs} +1 -1
- package/dist/{seo-BkhuuaaE.mjs.map → seo-89-53DDs.mjs.map} +1 -1
- package/dist/{seo-DKeXHkzE.mjs → seo-DXu2UQnC.mjs} +3 -3
- package/dist/{seo-DKeXHkzE.mjs.map → seo-DXu2UQnC.mjs.map} +1 -1
- package/dist/{service-BbO2s8gT.mjs → service-DQmiBMzt.mjs} +3 -3
- package/dist/{service-BbO2s8gT.mjs.map → service-DQmiBMzt.mjs.map} +1 -1
- package/dist/{session-user-B8aLtKAH.mjs → session-user-Cascbax7.mjs} +1 -1
- package/dist/{session-user-B8aLtKAH.mjs.map → session-user-Cascbax7.mjs.map} +1 -1
- package/dist/{settings-BMNr9Dmi.mjs → settings-rZyHEcNT.mjs} +3 -3
- package/dist/{settings-BMNr9Dmi.mjs.map → settings-rZyHEcNT.mjs.map} +1 -1
- package/dist/{settings-DJeki-97.mjs → settings-zhmdKyJQ.mjs} +5 -5
- package/dist/{settings-DJeki-97.mjs.map → settings-zhmdKyJQ.mjs.map} +1 -1
- package/dist/{setup-complete-gEiySUc-.mjs → setup-complete-Cb3LRyzy.mjs} +1 -1
- package/dist/{setup-complete-gEiySUc-.mjs.map → setup-complete-Cb3LRyzy.mjs.map} +1 -1
- package/dist/{setup-nonce-DzS50zme.mjs → setup-nonce-Z8x0tHf8.mjs} +1 -1
- package/dist/{setup-nonce-DzS50zme.mjs.map → setup-nonce-Z8x0tHf8.mjs.map} +1 -1
- package/dist/{single-flight-cache-Cdfkic3t.mjs → single-flight-cache-BG3B_GhN.mjs} +1 -1
- package/dist/{single-flight-cache-Cdfkic3t.mjs.map → single-flight-cache-BG3B_GhN.mjs.map} +1 -1
- package/dist/{site-url-BLebyON8.mjs → site-url-BBfDTgZB.mjs} +1 -1
- package/dist/{site-url-BLebyON8.mjs.map → site-url-BBfDTgZB.mjs.map} +1 -1
- package/dist/{ssrf-BRKb343l.mjs → ssrf-1g7usGBg.mjs} +1 -1
- package/dist/{ssrf-BRKb343l.mjs.map → ssrf-1g7usGBg.mjs.map} +1 -1
- package/dist/{status-vUK0SA17.mjs → status-CqJQX1QN.mjs} +1 -1
- package/dist/{status-vUK0SA17.mjs.map → status-CqJQX1QN.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-CM_fUqLU.mjs → taxonomies-BGBd16Eu.mjs} +4 -4
- package/dist/{taxonomies-CM_fUqLU.mjs.map → taxonomies-BGBd16Eu.mjs.map} +1 -1
- package/dist/{taxonomies-D13i2ctt.mjs → taxonomies-Cnb4F-Pb.mjs} +7 -7
- package/dist/{taxonomies-D13i2ctt.mjs.map → taxonomies-Cnb4F-Pb.mjs.map} +1 -1
- package/dist/{taxonomy-BU0LjdVb.mjs → taxonomy-BxGxZZdu.mjs} +4 -4
- package/dist/{taxonomy-BU0LjdVb.mjs.map → taxonomy-BxGxZZdu.mjs.map} +1 -1
- package/dist/{tokens-LeuXF9gG.mjs → tokens-BGT0TUUo.mjs} +1 -1
- package/dist/{tokens-LeuXF9gG.mjs.map → tokens-BGT0TUUo.mjs.map} +1 -1
- package/dist/{transport-BZ-03aFT.d.mts → transport-BMDWHSgZ.d.mts} +1 -1
- package/dist/{transport-BZ-03aFT.d.mts.map → transport-BMDWHSgZ.d.mts.map} +1 -1
- package/dist/{transport-_2nBz7e9.mjs → transport-DPefPMcz.mjs} +1 -1
- package/dist/{transport-_2nBz7e9.mjs.map → transport-DPefPMcz.mjs.map} +1 -1
- package/dist/{trusted-proxy-DZY5WCn2.mjs → trusted-proxy-VTPRiX2s.mjs} +1 -1
- package/dist/{trusted-proxy-DZY5WCn2.mjs.map → trusted-proxy-VTPRiX2s.mjs.map} +1 -1
- package/dist/{types-ETmO_jQr.d.mts → types-BcLUUbbR.d.mts} +2 -2
- package/dist/{types-ETmO_jQr.d.mts.map → types-BcLUUbbR.d.mts.map} +1 -1
- package/dist/{types-BYnDBVwe.d.mts → types-CGbYowGQ.d.mts} +2 -2
- package/dist/{types-BYnDBVwe.d.mts.map → types-CGbYowGQ.d.mts.map} +1 -1
- package/dist/{types-BWqGVhFn.d.mts → types-CgvhU-hF.d.mts} +1 -1
- package/dist/{types-BWqGVhFn.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
- package/dist/{types-fS7-VTdR.d.mts → types-ClUkdbWb.d.mts} +1 -1
- package/dist/{types-fS7-VTdR.d.mts.map → types-ClUkdbWb.d.mts.map} +1 -1
- package/dist/{types-CZgK3EMW.mjs → types-CuW0zWDA.mjs} +2 -2
- package/dist/{types-CZgK3EMW.mjs.map → types-CuW0zWDA.mjs.map} +1 -1
- package/dist/{types-BG8_XTLj.d.mts → types-DmHk7vAt.d.mts} +1 -1
- package/dist/{types-BG8_XTLj.d.mts.map → types-DmHk7vAt.d.mts.map} +1 -1
- package/dist/{types-CQAugunJ.mjs → types-Jo3UYd6b.mjs} +1 -1
- package/dist/{types-CQAugunJ.mjs.map → types-Jo3UYd6b.mjs.map} +1 -1
- package/dist/{types-xIfVRNLp.d.mts → types-_HFLRzTn.d.mts} +22 -1
- package/dist/types-_HFLRzTn.d.mts.map +1 -0
- package/dist/{types-DrYMm9s5.d.mts → types-ea9sAPck.d.mts} +1 -1
- package/dist/{types-DrYMm9s5.d.mts.map → types-ea9sAPck.d.mts.map} +1 -1
- package/dist/{types-CNlaBFzx.d.mts → types-g_aFIdW0.d.mts} +1 -1
- package/dist/{types-CNlaBFzx.d.mts.map → types-g_aFIdW0.d.mts.map} +1 -1
- package/dist/{types-CUsXGRVj.d.mts → types-vgEWF18A.d.mts} +19 -1
- package/dist/{types-CUsXGRVj.d.mts.map → types-vgEWF18A.d.mts.map} +1 -1
- package/dist/{user-DkG2jKCp.mjs → user-BjAOvU3Z.mjs} +3 -3
- package/dist/{user-DkG2jKCp.mjs.map → user-BjAOvU3Z.mjs.map} +1 -1
- package/dist/{utils-B7A57fm9.mjs → utils-BJXElxdw.mjs} +156 -7
- package/dist/utils-BJXElxdw.mjs.map +1 -0
- package/dist/{validate-CuJ1Ps9j.mjs → validate-CWSnKVIJ.mjs} +2 -2
- package/dist/{validate-CuJ1Ps9j.mjs.map → validate-CWSnKVIJ.mjs.map} +1 -1
- package/dist/{validate-CG0V0wNR.d.mts → validate-Z1b86_3B.d.mts} +11 -6
- package/dist/{validate-CG0V0wNR.d.mts.map → validate-Z1b86_3B.d.mts.map} +1 -1
- package/dist/{validation-CwUfTdGF.mjs → validation-c8WjhH8z.mjs} +8 -5
- package/dist/{validation-CwUfTdGF.mjs.map → validation-c8WjhH8z.mjs.map} +1 -1
- package/dist/version-CaccU7DM.mjs +7 -0
- package/dist/{version-BoNBItP_.mjs.map → version-CaccU7DM.mjs.map} +1 -1
- package/dist/{widgets-BfOZ-ajY.mjs → widgets-hWcIicX8.mjs} +3 -3
- package/dist/{widgets-BfOZ-ajY.mjs.map → widgets-hWcIicX8.mjs.map} +1 -1
- package/dist/wxr-taxonomies-0_uxSrmf.d.mts +34 -0
- package/dist/wxr-taxonomies-0_uxSrmf.d.mts.map +1 -0
- package/dist/wxr-taxonomies-BC3OYpvx.mjs +425 -0
- package/dist/wxr-taxonomies-BC3OYpvx.mjs.map +1 -0
- package/dist/{zod-generator-gFsRuNNy.mjs → zod-generator-CacrR-i8.mjs} +2 -2
- package/dist/{zod-generator-gFsRuNNy.mjs.map → zod-generator-CacrR-i8.mjs.map} +1 -1
- package/package.json +6 -6
- package/src/api/handlers/content.ts +69 -23
- package/src/api/handlers/plugins.ts +77 -10
- package/src/api/schemas/import.ts +19 -0
- package/src/astro/integration/runtime.ts +3 -6
- package/src/astro/integration/vite-config.ts +19 -1
- package/src/astro/middleware/auth.ts +10 -3
- package/src/astro/middleware/csp.ts +54 -3
- package/src/astro/middleware.ts +1 -0
- package/src/astro/routes/admin.astro +9 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +6 -1
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +6 -1
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +1 -0
- package/src/astro/routes/api/admin/plugins/index.ts +1 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +122 -98
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +794 -44
- package/src/astro/routes/api/manifest.ts +20 -1
- package/src/astro/routes/api/setup/dev-bypass.ts +7 -2
- package/src/astro/types.ts +4 -0
- package/src/cli/commands/seed.ts +1 -1
- package/src/components/EmDashImage.astro +59 -23
- package/src/components/Image.astro +36 -35
- package/src/components/LiveSearch.astro +40 -4
- package/src/components/live-search-routing.ts +30 -0
- package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +23 -18
- package/src/database/migrations/048_restore_content_taxonomies_term_index.ts +32 -0
- package/src/database/migrations/049_taxonomies_name_locale_index.ts +42 -0
- package/src/database/migrations/050_media_usage_index_status.ts +142 -0
- package/src/database/migrations/runner.ts +6 -0
- package/src/database/repositories/media-usage.ts +932 -58
- package/src/database/types.ts +22 -0
- package/src/emdash-runtime.ts +123 -3
- package/src/import/comments.ts +159 -0
- package/src/import/index.ts +8 -1
- package/src/import/settings.ts +65 -189
- package/src/import/sources/wordpress-plugin.ts +338 -42
- package/src/import/sources/wxr.ts +4 -1
- package/src/import/types.ts +12 -0
- package/src/import/utils.ts +207 -0
- package/src/import/wxr-taxonomies.ts +39 -0
- package/src/loader.ts +13 -2
- package/src/media/usage/content-fields.ts +119 -0
- package/src/media/usage/content-refresh.ts +524 -0
- package/src/media/usage/content-repair.ts +491 -0
- package/src/media/usage/content-snapshots.ts +435 -0
- package/src/media/usage/extractor.ts +4 -4
- package/src/media/usage/source-key.ts +22 -0
- package/src/menus/index.ts +17 -1
- package/src/object-cache/index.ts +82 -7
- package/src/plugins/context.ts +100 -71
- package/src/schema/registry.ts +240 -154
- package/src/search/query.ts +3 -0
- package/src/search/types.ts +2 -0
- package/src/seed/apply.ts +158 -101
- package/src/seed/types.ts +6 -1
- package/dist/api-BMfveMoB.mjs.map +0 -1
- package/dist/apply--IVNSdXn.mjs.map +0 -1
- package/dist/byline-fields-eyJMblSr.mjs.map +0 -1
- package/dist/context-C_g-iJVA.mjs.map +0 -1
- package/dist/import-Bb1T9WJS.mjs.map +0 -1
- package/dist/index-BRNabKrx.d.mts.map +0 -1
- package/dist/index-Dt0OKJB4.d.mts.map +0 -1
- package/dist/loader-BA_zhkS_.mjs.map +0 -1
- package/dist/object-cache-CHbHv83-.mjs.map +0 -1
- package/dist/registry-g8yYt4cC.mjs.map +0 -1
- package/dist/runner-DPdt_Wpa.mjs.map +0 -1
- package/dist/search-BR0ZeZmh.mjs.map +0 -1
- package/dist/types-xIfVRNLp.d.mts.map +0 -1
- package/dist/utils-B7A57fm9.mjs.map +0 -1
- package/dist/version-BoNBItP_.mjs +0 -7
- /package/dist/{api-tokens-B4BQybOp.mjs → api-tokens-DsvvCtdh.mjs} +0 -0
- /package/dist/{ssrf-CcX9zvMK.mjs → ssrf-CmuGgCq3.mjs} +0 -0
- /package/dist/{types-BvbeGEtr.mjs → types-DROWRxYV.mjs} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"object-cache-CHbHv83-.mjs","names":[],"sources":["../src/object-cache/codec.ts","../src/object-cache/index.ts"],"sourcesContent":["/**\n * Object-cache serialization codec.\n *\n * Cached values are JSON, with one extension: `Date` instances are preserved\n * across the round-trip. EmDash content entries carry `Date` objects for the\n * system timestamp columns (`createdAt`, `updatedAt`, `publishedAt`,\n * `scheduledAt`) and on `cacheHint.lastModified`; plain `JSON.stringify` would\n * silently flatten those to ISO strings, so a value read from cache would no\n * longer be `=== instanceof Date` and downstream `value instanceof Date`\n * branches (cursor encoding, scheduled-visibility checks) would diverge from a\n * fresh database read.\n *\n * Functions and symbol-keyed properties are NOT preserved — callers that cache\n * values carrying either (e.g. content entries with their `.edit` proxy and\n * the non-enumerable `CURSOR_RAW_VALUES` symbol) must reduce to a serializable\n * snapshot before caching and rebuild the non-serializable parts on read. See\n * `query.ts` content snapshot helpers.\n */\n\n/** Tag used to mark a serialized `Date`. Deliberately unlikely to collide. */\nconst DATE_TAG = \"$$emdashDate\";\n\ninterface TaggedDate {\n\t[DATE_TAG]: string;\n}\n\nfunction isTaggedDate(value: unknown): value is TaggedDate {\n\tif (typeof value !== \"object\" || value === null) return false;\n\t// encode() always emits the tag as the object's *only* key, so requiring\n\t// exactly one key keeps a user object that merely happens to carry a\n\t// `$$emdashDate` string alongside other fields from being collapsed to a\n\t// Date (which would silently drop those other fields).\n\tconst keys = Object.keys(value);\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowing a JSON-parsed value to read the date tag\n\treturn keys.length === 1 && typeof (value as Record<string, unknown>)[DATE_TAG] === \"string\";\n}\n\n/**\n * Serialize a value to a cache string, preserving `Date` instances.\n *\n * Uses the JSON replacer's `this` binding to inspect the *original* property\n * value: `JSON.stringify` invokes `Date.prototype.toJSON` before the replacer\n * sees it, so by the time `value` arrives it is already an ISO string. Reading\n * `this[key]` recovers the live `Date` so we can tag it.\n */\nexport function encode(value: unknown): string {\n\treturn JSON.stringify(value, function (this: Record<string, unknown>, key, val) {\n\t\tconst original = this[key];\n\t\tif (original instanceof Date) {\n\t\t\treturn { [DATE_TAG]: original.toISOString() } satisfies TaggedDate;\n\t\t}\n\t\treturn val;\n\t});\n}\n\n/**\n * Parse a cache string produced by {@link encode}, rehydrating tagged `Date`s.\n *\n * Returns `undefined` if the input is not valid JSON (treated as a cache miss\n * by the read-through layer rather than throwing).\n */\nexport function decode(raw: string): unknown {\n\ttry {\n\t\treturn JSON.parse(raw, (_key, value) => {\n\t\t\tif (isTaggedDate(value)) {\n\t\t\t\treturn new Date(value[DATE_TAG]);\n\t\t\t}\n\t\t\treturn value;\n\t\t});\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n","/**\n * Object cache — distributed read-through query cache.\n *\n * Layering (per query):\n *\n * requestCached → in-request dedupe (per render, WeakMap on ALS context)\n * cachedQuery → THIS layer: distributed L2 (KV / memory), epoch-keyed\n * database → source of truth\n *\n * Optional and off by default: when no `objectCache` descriptor is configured,\n * `virtual:emdash/object-cache` exports `createObjectCache = undefined`,\n * {@link getBackend} resolves to `null`, and {@link cachedQuery} is a\n * transparent passthrough to its `load` function. Configure with\n * `memoryCache()` (Node) or `kvCache()` from `@emdash-cms/cloudflare`.\n *\n * Invalidation is epoch-based: each cache key embeds a per-namespace epoch\n * (\"last changed\" marker) read from the backend. A write calls\n * {@link invalidateObjectCache}, which stamps the namespace epoch to\n * `Date.now()`; every previously-stored key for that namespace is instantly\n * orphaned and reclaimed by its TTL. This is O(1) and needs no key\n * enumeration (KV has no prefix delete).\n *\n * The singleton backend/config and the per-isolate epoch cache live on\n * `globalThis` behind `Symbol.for` keys so Vite SSR chunk duplication can't\n * fork them (same pattern as `request-context.ts`).\n */\n\nimport { after } from \"../after.js\";\nimport { getRequestContext } from \"../request-context.js\";\nimport { decode, encode } from \"./codec.js\";\nimport type {\n\tCreateObjectCacheBackendFn,\n\tObjectCacheBackend,\n\tObjectCacheRuntimeConfig,\n} from \"./types.js\";\n\nconst DEFAULT_KEY_PREFIX = \"em\";\nconst DEFAULT_TTL_SECONDS = 3600;\nconst DEFAULT_REVALIDATE_MS = 1000;\nconst DEFAULT_TIMEOUT_MS = 2000;\n\ninterface BackendHolder {\n\t/** Whether the virtual module has been loaded and the backend resolved. */\n\tinitialized: boolean;\n\t/** Resolved backend, or `null` when no object cache is configured. */\n\tbackend: ObjectCacheBackend | null;\n\t/** In-flight initialization promise (dedupes concurrent first calls). */\n\tinitPromise: Promise<ObjectCacheBackend | null> | null;\n\tconfig: Required<Pick<ObjectCacheRuntimeConfig, \"keyPrefix\">> & {\n\t\tdefaultTtl: number;\n\t\trevalidate: number;\n\t\ttimeout: number;\n\t};\n}\n\n/**\n * Race a backend operation against a timeout so a stalled call (e.g. a KV read\n * that never resolves *and* never rejects — a cold cross-region read, or one\n * queued behind the Workers simultaneous-connection limit) degrades to a\n * rejection instead of hanging the isolate. A rejection is benign: callers\n * already treat a failed read as a cache miss / last-known epoch.\n */\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n\tif (!(ms > 0)) return promise;\n\tlet timer: ReturnType<typeof setTimeout>;\n\tconst timeout = new Promise<never>((_resolve, reject) => {\n\t\ttimer = setTimeout(() => {\n\t\t\treject(new Error(`object-cache ${label} timed out after ${ms}ms`));\n\t\t}, ms);\n\t});\n\treturn Promise.race([promise, timeout]).finally(() => clearTimeout(timer));\n}\n\ninterface EpochEntry {\n\tvalue: number;\n\t/** `Date.now()` at which this epoch was read from the backend. */\n\tat: number;\n\t/** In-flight read, so concurrent callers share one backend round-trip. */\n\tpromise?: Promise<number>;\n}\n\nconst BACKEND_KEY = Symbol.for(\"emdash:object-cache:backend\");\nconst EPOCH_KEY = Symbol.for(\"emdash:object-cache:epochs\");\nconst PENDING_KEY = Symbol.for(\"emdash:object-cache:pending-bumps\");\nconst g = globalThis as Record<symbol, unknown>;\n\nconst holder: BackendHolder =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)\n\t(g[BACKEND_KEY] as BackendHolder | undefined) ??\n\t(() => {\n\t\tconst h: BackendHolder = {\n\t\t\tinitialized: false,\n\t\t\tbackend: null,\n\t\t\tinitPromise: null,\n\t\t\tconfig: {\n\t\t\t\tkeyPrefix: DEFAULT_KEY_PREFIX,\n\t\t\t\tdefaultTtl: DEFAULT_TTL_SECONDS,\n\t\t\t\trevalidate: DEFAULT_REVALIDATE_MS,\n\t\t\t\ttimeout: DEFAULT_TIMEOUT_MS,\n\t\t\t},\n\t\t};\n\t\tg[BACKEND_KEY] = h;\n\t\treturn h;\n\t})();\n\nconst epochCache: Map<string, EpochEntry> =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)\n\t(g[EPOCH_KEY] as Map<string, EpochEntry> | undefined) ??\n\t(() => {\n\t\tconst m = new Map<string, EpochEntry>();\n\t\tg[EPOCH_KEY] = m;\n\t\treturn m;\n\t})();\n\n/** Namespaces with a backend epoch write already scheduled this tick. */\nconst pendingBumps: Set<string> =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)\n\t(g[PENDING_KEY] as Set<string> | undefined) ??\n\t(() => {\n\t\tconst s = new Set<string>();\n\t\tg[PENDING_KEY] = s;\n\t\treturn s;\n\t})();\n\n/**\n * Resolve (once per isolate) the configured object-cache backend.\n *\n * Loads `virtual:emdash/object-cache`, which exports `createObjectCache`\n * (`undefined` when no cache is configured) and the serialized\n * `objectCacheConfig`. Returns `null` when the cache is disabled.\n */\nasync function getBackend(): Promise<ObjectCacheBackend | null> {\n\tif (holder.initialized) return holder.backend;\n\tif (holder.initPromise) return holder.initPromise;\n\n\tholder.initPromise = (async () => {\n\t\ttry {\n\t\t\tconst mod: {\n\t\t\t\tcreateObjectCache?: CreateObjectCacheBackendFn;\n\t\t\t\tobjectCacheConfig?: ObjectCacheRuntimeConfig;\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t\t\t// @ts-ignore - virtual module\n\t\t\t} = await import(\"virtual:emdash/object-cache\");\n\n\t\t\tconst config = mod.objectCacheConfig ?? {};\n\t\t\tholder.config = {\n\t\t\t\tkeyPrefix:\n\t\t\t\t\ttypeof config.keyPrefix === \"string\" && config.keyPrefix.length > 0\n\t\t\t\t\t\t? config.keyPrefix\n\t\t\t\t\t\t: DEFAULT_KEY_PREFIX,\n\t\t\t\tdefaultTtl:\n\t\t\t\t\ttypeof config.defaultTtl === \"number\" && config.defaultTtl > 0\n\t\t\t\t\t\t? config.defaultTtl\n\t\t\t\t\t\t: DEFAULT_TTL_SECONDS,\n\t\t\t\trevalidate:\n\t\t\t\t\ttypeof config.revalidate === \"number\" && config.revalidate >= 0\n\t\t\t\t\t\t? config.revalidate\n\t\t\t\t\t\t: DEFAULT_REVALIDATE_MS,\n\t\t\t\ttimeout:\n\t\t\t\t\ttypeof config.timeout === \"number\" && config.timeout >= 0\n\t\t\t\t\t\t? config.timeout\n\t\t\t\t\t\t: DEFAULT_TIMEOUT_MS,\n\t\t\t};\n\n\t\t\tholder.backend =\n\t\t\t\ttypeof mod.createObjectCache === \"function\" ? mod.createObjectCache(config) : null;\n\t\t} catch (error) {\n\t\t\t// Importing the virtual module fails outside an Astro/Vite context\n\t\t\t// (e.g. unit tests, CLI). Treat as \"no cache configured\".\n\t\t\tif (import.meta.env?.DEV) {\n\t\t\t\tconsole.warn(\"[object-cache] backend unavailable:\", error);\n\t\t\t}\n\t\t\tholder.backend = null;\n\t\t}\n\t\tholder.initialized = true;\n\t\tholder.initPromise = null;\n\t\treturn holder.backend;\n\t})();\n\n\treturn holder.initPromise;\n}\n\n/**\n * Test-only override of the backend, bypassing the virtual module.\n *\n * Lets unit tests inject an in-memory backend (and optional config) without a\n * full Astro/Vite build. Pass `null` to simulate \"no cache configured\".\n *\n * @internal\n */\nexport function __setObjectCacheBackendForTests(\n\tbackend: ObjectCacheBackend | null,\n\tconfig?: Partial<BackendHolder[\"config\"]>,\n): void {\n\tholder.initialized = true;\n\tholder.initPromise = null;\n\tholder.backend = backend;\n\tholder.config = { ...holder.config, ...config };\n\tepochCache.clear();\n}\n\n/** Build the backend key for a namespace's epoch anchor. */\nfunction epochKey(namespace: string): string {\n\treturn `${holder.config.keyPrefix}:epoch:${namespace}`;\n}\n\n/**\n * Build the (epoch-independent) backend key for a cached value.\n *\n * The key is stable across invalidations — the namespace epochs are stored\n * *inside* the value envelope and validated on read, not baked into the key.\n * This lets the value and the epochs be fetched in one parallel round-trip\n * (instead of \"read epoch, then read value\"), and means an invalidated value\n * is overwritten in place rather than orphaned under a dead epoch-keyed name.\n */\nfunction valueKey(namespaces: readonly string[], key: string): string {\n\treturn `${holder.config.keyPrefix}:${namespaces.join(\",\")}:${key}`;\n}\n\n/**\n * Stored cache envelope: the namespace epochs captured at write time alongside\n * the cached value. A read is a HIT only when every stored epoch still matches\n * the current epoch for its namespace.\n */\ninterface CacheEnvelope<T> {\n\t/** Epoch per namespace, in the query's namespace order. */\n\te: number[];\n\t/** The cached value. */\n\tv: T;\n}\n\nfunction epochsMatch(stored: readonly number[], current: readonly number[]): boolean {\n\tif (stored.length !== current.length) return false;\n\tfor (let i = 0; i < stored.length; i++) {\n\t\tif (stored[i] !== current[i]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Requests that must always read live data and never populate the cache:\n * visual edit mode, preview tokens, and isolated databases (playground / DO\n * preview, whose schema and content diverge from the configured site).\n */\nfunction shouldBypass(): boolean {\n\tconst ctx = getRequestContext();\n\tif (!ctx) return false;\n\treturn ctx.editMode === true || ctx.preview !== undefined || ctx.dbIsIsolated === true;\n}\n\n/**\n * Read the current epoch for `namespace`, reusing an isolate-cached value for\n * up to `revalidate` ms. A missing epoch (never bumped) is treated as `0`.\n *\n * Backend errors and stalls are non-fatal: the read is bounded by a timeout,\n * and on failure we fall back to the last known epoch (or `0`), so a flaky or\n * hung cache degrades to \"serve whatever's keyed\" rather than throwing or\n * hanging.\n */\nasync function getEpoch(namespace: string, backend: ObjectCacheBackend): Promise<number> {\n\tconst now = Date.now();\n\tconst cached = epochCache.get(namespace);\n\tif (cached && now - cached.at < holder.config.revalidate) {\n\t\treturn cached.value;\n\t}\n\tif (cached?.promise) return cached.promise;\n\n\tconst promise = (async () => {\n\t\tlet value: number;\n\t\ttry {\n\t\t\tconst raw = await withTimeout(\n\t\t\t\tbackend.get(epochKey(namespace)),\n\t\t\t\tholder.config.timeout,\n\t\t\t\t\"epoch read\",\n\t\t\t);\n\t\t\tconst parsed = raw === null ? 0 : Number(raw);\n\t\t\tvalue = Number.isFinite(parsed) ? parsed : 0;\n\t\t} catch {\n\t\t\tvalue = cached?.value ?? 0;\n\t\t}\n\t\t// A concurrent invalidateObjectCache may have bumped the epoch while this\n\t\t// read was in flight. Epochs are monotonic, so never let a stale backend\n\t\t// read lower a freshly-bumped local epoch — that would resurrect the very\n\t\t// values the bump just invalidated.\n\t\tconst merged = Math.max(value, epochCache.get(namespace)?.value ?? 0);\n\t\tepochCache.set(namespace, { value: merged, at: Date.now() });\n\t\treturn merged;\n\t})();\n\n\t// Concurrent callers share this in-flight read (dedup). The timeout above\n\t// guarantees `promise` settles — its success/catch handler then replaces\n\t// this entry with a fresh, promise-free one — so a stalled backend can no\n\t// longer pin the namespace to a never-settling promise (the bug that\n\t// poisoned an isolate until it was recycled).\n\tepochCache.set(namespace, { value: cached?.value ?? 0, at: cached?.at ?? 0, promise });\n\treturn promise;\n}\n\n/** Options for {@link cachedQuery}. */\nexport interface CachedQueryOptions<T> {\n\t/**\n\t * Invalidation namespace(s). A single string for self-contained data\n\t * (`settings`, `menus`), or several when the cached value depends on data\n\t * owned by other namespaces — e.g. a content entry hydrates bylines and\n\t * taxonomy terms, so it caches under\n\t * `[content:posts, \"bylines\", \"taxonomies\"]` and is invalidated when *any*\n\t * of them is bumped. Every namespace's epoch is folded into the key.\n\t */\n\tnamespace: string | readonly string[];\n\t/** Stable, fully-qualifying cache key *within* the namespace. */\n\tkey: string;\n\t/** Loader run on a miss (or when caching is disabled/bypassed). */\n\tload: () => Promise<T>;\n\t/** TTL override in seconds. Falls back to the configured `defaultTtl`. */\n\tttl?: number;\n\t/**\n\t * Predicate gating whether a freshly-loaded value is stored. Defaults to\n\t * always-cache. Use it to skip caching error/empty sentinels.\n\t */\n\tcacheable?: (value: T) => boolean;\n}\n\n/**\n * Distributed read-through cache around `load`.\n *\n * `T` must be the value as it should be *stored* — i.e. JSON-serializable with\n * the codec's `Date` support, carrying no functions or symbol-keyed props.\n * Callers caching richer objects (content entries) reduce to a serializable\n * snapshot here and rebuild on the way out; see `query.ts`.\n *\n * On a miss or when the cache is disabled/bypassed, this is equivalent to\n * `await load()`. Backend errors never propagate: a failing `get` is a miss, a\n * failing `set` is dropped.\n */\nexport async function cachedQuery<T>(options: CachedQueryOptions<T>): Promise<T> {\n\tconst backend = await getBackend();\n\tif (!backend || shouldBypass()) {\n\t\treturn options.load();\n\t}\n\n\tconst namespaces =\n\t\ttypeof options.namespace === \"string\" ? [options.namespace] : options.namespace;\n\tconst fullKey = valueKey(namespaces, options.key);\n\n\t// Kick off the value read and every namespace epoch read concurrently — one\n\t// round-trip instead of \"read epochs, then read value\". getEpoch never\n\t// rejects, so awaiting the epochs separately from the value read guarantees\n\t// we hold the pre-load epochs even when the value read errors or times out.\n\t// Storing a value under an epoch read *after* load() would mask a write that\n\t// landed during load(): the stale value would match and be served as a HIT.\n\tconst epochsPromise = Promise.all(namespaces.map((ns) => getEpoch(ns, backend)));\n\tconst rawPromise = withTimeout(backend.get(fullKey), holder.config.timeout, \"read\").catch(\n\t\t() => null,\n\t);\n\tconst currentEpochs = await epochsPromise;\n\tconst raw = await rawPromise;\n\tif (raw !== null) {\n\t\tconst decoded = decode(raw);\n\t\tif (decoded !== undefined) {\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- value envelope written by this function\n\t\t\tconst envelope = decoded as CacheEnvelope<T>;\n\t\t\tif (epochsMatch(envelope.e, currentEpochs)) {\n\t\t\t\treturn envelope.v;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst value = await options.load();\n\n\tconst cacheable = options.cacheable ? options.cacheable(value) : true;\n\tif (cacheable) {\n\t\tconst ttl = options.ttl ?? holder.config.defaultTtl;\n\t\t// Defer the write so it never adds to TTFB. The epochs were captured\n\t\t// before load() ran, so a write that invalidated this namespace mid-load\n\t\t// correctly orphans the value stored here.\n\t\tafter(async () => {\n\t\t\ttry {\n\t\t\t\tconst encoded = encode({ e: currentEpochs, v: value } satisfies CacheEnvelope<T>);\n\t\t\t\tawait backend.set(fullKey, encoded, ttl);\n\t\t\t} catch (error) {\n\t\t\t\tif (import.meta.env?.DEV) {\n\t\t\t\t\tconsole.warn(\"[object-cache] set failed:\", error);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\treturn value;\n}\n\n/** Whether object-cache reads are active for the current request. */\nexport async function isObjectCacheActive(): Promise<boolean> {\n\tconst backend = await getBackend();\n\treturn backend !== null && !shouldBypass();\n}\n\n/**\n * Invalidate every cached value in `namespace` by bumping its epoch.\n *\n * Sync and non-blocking: the local epoch is stamped immediately (so the\n * writing isolate is instantly consistent) and the backend write is deferred\n * via `after`. Other isolates pick up the new epoch within their `revalidate`\n * window. No-ops when the cache is disabled.\n */\nexport function invalidateObjectCache(namespace: string): void {\n\t// Monotonic so two writes in the same millisecond still produce distinct\n\t// epochs — otherwise the second write reuses the first's stamp and its\n\t// stale entries survive.\n\tconst prev = epochCache.get(namespace)?.value ?? 0;\n\tconst stamp = Math.max(prev + 1, Date.now());\n\t// Optimistic local bump: keep this isolate consistent without a round-trip.\n\tepochCache.set(namespace, { value: stamp, at: stamp });\n\n\t// Coalesce repeated bumps of the same namespace within a tick (e.g. a bulk\n\t// publish loop) into a single backend write that persists the latest epoch.\n\tif (pendingBumps.has(namespace)) return;\n\tpendingBumps.add(namespace);\n\tafter(async () => {\n\t\tpendingBumps.delete(namespace);\n\t\ttry {\n\t\t\tconst backend = await getBackend();\n\t\t\tif (!backend) return;\n\t\t\tconst latest = epochCache.get(namespace)?.value ?? stamp;\n\t\t\t// Epoch anchors are persistent (no TTL) — they must outlive the\n\t\t\t// value keys they invalidate.\n\t\t\tawait backend.set(epochKey(namespace), String(latest));\n\t\t} catch (error) {\n\t\t\tconsole.error(\"[object-cache] epoch bump failed for\", namespace, error);\n\t\t}\n\t});\n}\n\n/**\n * Fixed namespaces for data shared across collections. Content reads fold the\n * `BYLINES` and `TAXONOMIES` epochs into their keys (via {@link cachedQuery})\n * because entries hydrate byline and taxonomy-term data — so renaming an\n * author or a category correctly invalidates every cached entry that displays\n * it, without tracking which collections reference it.\n */\nexport const CacheNamespace = {\n\tSETTINGS: \"settings\",\n\tMENUS: \"menus\",\n\tTAXONOMIES: \"taxonomies\",\n\tBYLINES: \"bylines\",\n\t/** Collection schema/metadata (label, supports, commentsEnabled, fields). */\n\tSCHEMA: \"schema\",\n\t/** Public (approved) comments. */\n\tCOMMENTS: \"comments\",\n} as const;\n\n/** Namespace for a content collection's cached queries. */\nexport function contentNamespace(collection: string): string {\n\treturn `content:${collection}`;\n}\n\n/**\n * Namespaces a content read depends on: the collection itself plus the shared\n * byline/taxonomy data folded into each entry.\n */\nexport function contentNamespaces(collection: string): readonly string[] {\n\treturn [contentNamespace(collection), CacheNamespace.BYLINES, CacheNamespace.TAXONOMIES];\n}\n\n/**\n * Invalidate all cached reads (list + entry) for a content collection.\n * Call from every write path that mutates rows in `ec_<collection>`.\n */\nexport function invalidateCollectionCache(collection: string): void {\n\tinvalidateObjectCache(contentNamespace(collection));\n}\n\n/** Invalidate cached taxonomy definitions/terms and all content that hydrates them. */\nexport function invalidateTaxonomyObjectCache(): void {\n\tinvalidateObjectCache(CacheNamespace.TAXONOMIES);\n}\n\n/** Invalidate cached bylines and all content that hydrates them. */\nexport function invalidateBylineObjectCache(): void {\n\tinvalidateObjectCache(CacheNamespace.BYLINES);\n}\n\n/** Invalidate cached navigation menus. */\nexport function invalidateMenuObjectCache(): void {\n\tinvalidateObjectCache(CacheNamespace.MENUS);\n}\n\n/** Invalidate cached collection schema/metadata reads (e.g. getCollectionInfo). */\nexport function invalidateSchemaObjectCache(): void {\n\tinvalidateObjectCache(CacheNamespace.SCHEMA);\n}\n\n/** Invalidate cached public comment reads. */\nexport function invalidateCommentObjectCache(): void {\n\tinvalidateObjectCache(CacheNamespace.COMMENTS);\n}\n\nexport type {\n\tObjectCacheBackend,\n\tObjectCacheDescriptor,\n\tObjectCacheRuntimeConfig,\n} from \"./types.js\";\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-g8yYt4cC.mjs","names":[],"sources":["../src/schema/registry.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\nimport type { Selectable } from \"kysely\";\nimport { sql } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { currentTimestamp, listTablesLike, tableExists } from \"../database/dialect-helpers.js\";\nimport { withTransaction } from \"../database/transaction.js\";\nimport type { CollectionTable, Database, FieldTable } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { FTSManager } from \"../search/fts-manager.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../utils/chunks.js\";\nimport {\n\ttype Collection,\n\ttype CollectionSource,\n\ttype CollectionSupport,\n\ttype ColumnType,\n\ttype Field,\n\ttype CreateCollectionInput,\n\ttype UpdateCollectionInput,\n\ttype CreateFieldInput,\n\ttype UpdateFieldInput,\n\ttype CollectionWithFields,\n\ttype FieldType,\n\tFIELD_TYPE_TO_COLUMN,\n\tRESERVED_FIELD_SLUGS,\n\tRESERVED_COLLECTION_SLUGS,\n} from \"./types.js\";\n\n// Regex patterns for schema registry\nconst SLUG_VALIDATION_PATTERN = /^[a-z][a-z0-9_]*$/;\nconst EC_PREFIX_PATTERN = /^ec_/;\nconst SINGLE_QUOTE_PATTERN = /'/g;\nconst UNDERSCORE_PATTERN = /_/g;\nconst WORD_BOUNDARY_PATTERN = /\\b\\w/g;\n\n/** Valid column types for runtime validation */\nconst COLUMN_TYPES: ReadonlySet<string> = new Set([\"TEXT\", \"REAL\", \"INTEGER\", \"JSON\"]);\n\n/** Valid collection source prefixes/values */\nconst VALID_SOURCES: ReadonlySet<string> = new Set([\"manual\", \"discovered\", \"seed\"]);\n\nfunction isCollectionSource(value: string): value is CollectionSource {\n\treturn VALID_SOURCES.has(value) || value.startsWith(\"template:\") || value.startsWith(\"import:\");\n}\n\nfunction isFieldType(value: string): value is FieldType {\n\treturn value in FIELD_TYPE_TO_COLUMN;\n}\n\nfunction isColumnType(value: string): value is ColumnType {\n\treturn COLUMN_TYPES.has(value);\n}\n\nconst VALID_COLLECTION_SUPPORTS: ReadonlySet<string> = new Set<CollectionSupport>([\n\t\"drafts\",\n\t\"revisions\",\n\t\"preview\",\n\t\"scheduling\",\n\t\"search\",\n\t\"seo\",\n]);\n\nfunction isCollectionSupport(value: unknown): value is CollectionSupport {\n\treturn typeof value === \"string\" && VALID_COLLECTION_SUPPORTS.has(value);\n}\n\n/**\n * Parse a collection's `supports` column (stored as a JSON array of\n * CollectionSupport keys). Unknown/invalid entries are filtered out so the\n * runtime value matches the declared `CollectionSupport[]` type.\n *\n * Throws on malformed JSON so corruption surfaces loudly; returns an empty\n * array only for explicitly null/empty values or non-array JSON.\n */\nfunction parseSupports(raw: string | null | undefined): CollectionSupport[] {\n\tif (!raw) return [];\n\tconst parsed: unknown = JSON.parse(raw);\n\tif (!Array.isArray(parsed)) return [];\n\treturn parsed.filter(isCollectionSupport);\n}\n\n/**\n * Error thrown when a schema operation fails\n */\nexport class SchemaError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic code: string,\n\t\tpublic details?: Record<string, unknown>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SchemaError\";\n\t}\n}\n\n/**\n * Schema Registry\n *\n * Manages collection and field definitions stored in D1.\n * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).\n */\nexport class SchemaRegistry {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t// ============================================\n\t// Collection Operations\n\t// ============================================\n\n\t/**\n\t * List all collections\n\t */\n\tasync listCollections(): Promise<Collection[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"slug\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map(this.mapCollectionRow);\n\t}\n\n\t/**\n\t * Get a collection by slug\n\t */\n\tasync getCollection(slug: string): Promise<Collection | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.selectAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.mapCollectionRow(row) : null;\n\t}\n\n\t/**\n\t * Get a collection with all its fields\n\t */\n\tasync getCollectionWithFields(slug: string): Promise<CollectionWithFields | null> {\n\t\tconst collection = await this.getCollection(slug);\n\t\tif (!collection) return null;\n\n\t\tconst fields = await this.listFields(collection.id);\n\n\t\treturn { ...collection, fields };\n\t}\n\n\t/**\n\t * List every collection together with its fields in O(1) query shapes\n\t * — one for collections, then one batched query for the fields of every\n\t * returned collection — instead of the N+1 pattern of `listCollections`\n\t * + per-collection `listFields`. The fields query is chunked at\n\t * `SQL_BATCH_SIZE` to stay under D1's bound-parameter limit, so on\n\t * sites with more than `SQL_BATCH_SIZE` collections the field fetch\n\t * becomes `ceil(collectionCount / SQL_BATCH_SIZE)` queries — still\n\t * a constant factor, not N+1. Typical sites have well under\n\t * `SQL_BATCH_SIZE` collections, so this is two queries in practice.\n\t *\n\t * Used by the manifest build, which previously paid N+1 round-trips on\n\t * every admin request. Each round-trip costs ~80–150ms against the D1\n\t * primary on a busy link, so a 10-collection site spent ~1 s rebuilding\n\t * a manifest that is now built fresh per admin request (no cache).\n\t */\n\tasync listCollectionsWithFields(): Promise<CollectionWithFields[]> {\n\t\tconst collectionRows = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"slug\", \"asc\")\n\t\t\t.execute();\n\n\t\tif (collectionRows.length === 0) return [];\n\n\t\tconst fieldsByCollection = new Map<string, Field[]>();\n\t\t// Chunk to stay under D1's bound-parameter limit. Typical sites have\n\t\t// well under SQL_BATCH_SIZE collections, so this is a single query\n\t\t// in practice; on larger sites it becomes a small constant number\n\t\t// of queries, never N+1.\n\t\tfor (const idChunk of chunks(\n\t\t\tcollectionRows.map((c) => c.id),\n\t\t\tSQL_BATCH_SIZE,\n\t\t)) {\n\t\t\tconst fieldRows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t\t.where(\"collection_id\", \"in\", idChunk)\n\t\t\t\t.selectAll()\n\t\t\t\t.orderBy(\"collection_id\", \"asc\")\n\t\t\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t\t\t.orderBy(\"created_at\", \"asc\")\n\t\t\t\t.execute();\n\t\t\tfor (const row of fieldRows) {\n\t\t\t\tconst list = fieldsByCollection.get(row.collection_id) ?? [];\n\t\t\t\tlist.push(this.mapFieldRow(row));\n\t\t\t\tfieldsByCollection.set(row.collection_id, list);\n\t\t\t}\n\t\t}\n\n\t\treturn collectionRows.map((c) => ({\n\t\t\t...this.mapCollectionRow(c),\n\t\t\tfields: fieldsByCollection.get(c.id) ?? [],\n\t\t}));\n\t}\n\n\t/**\n\t * Create a new collection\n\t */\n\tasync createCollection(input: CreateCollectionInput): Promise<Collection> {\n\t\t// Validate slug\n\t\tthis.validateSlug(input.slug, \"collection\");\n\t\tif (RESERVED_COLLECTION_SLUGS.includes(input.slug)) {\n\t\t\tthrow new SchemaError(`Collection slug \"${input.slug}\" is reserved`, \"RESERVED_SLUG\");\n\t\t}\n\n\t\t// Check if collection already exists\n\t\tconst existing = await this.getCollection(input.slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(`Collection \"${input.slug}\" already exists`, \"COLLECTION_EXISTS\");\n\t\t}\n\n\t\tconst id = ulid();\n\n\t\t// Default `supports` to drafts + revisions when the caller didn't\n\t\t// specify it. Explicit empty array (`[]`) is preserved as an opt-out\n\t\t// — only `undefined` triggers the default. This is the canonical\n\t\t// default for new collections; the MCP and admin UI layers used to\n\t\t// duplicate this default but now defer to the registry.\n\t\tconst supports = input.supports ?? [\"drafts\", \"revisions\"];\n\n\t\t// Insert collection record and create content table in a transaction\n\t\t// so a failure in table creation doesn't leave an orphaned row.\n\t\t// Uses withTransaction for D1 compatibility (no transaction support).\n\t\t// Derive hasSeo from supports array if not explicitly set\n\t\tconst hasSeo = input.hasSeo ?? supports.includes(\"seo\") ?? false;\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\tawait trx\n\t\t\t\t.insertInto(\"_emdash_collections\")\n\t\t\t\t.values({\n\t\t\t\t\tid,\n\t\t\t\t\tslug: input.slug,\n\t\t\t\t\tlabel: input.label,\n\t\t\t\t\tlabel_singular: input.labelSingular ?? null,\n\t\t\t\t\tdescription: input.description ?? null,\n\t\t\t\t\ticon: input.icon ?? null,\n\t\t\t\t\tsupports: JSON.stringify(supports),\n\t\t\t\t\tsource: input.source ?? \"manual\",\n\t\t\t\t\thas_seo: hasSeo ? 1 : 0,\n\t\t\t\t\tcomments_enabled: input.commentsEnabled ? 1 : 0,\n\t\t\t\t\turl_pattern: input.urlPattern ?? null,\n\t\t\t\t})\n\t\t\t\t.execute();\n\n\t\t\t// Create the content table for this collection\n\t\t\tawait this.createContentTable(input.slug, trx);\n\t\t});\n\n\t\tconst collection = await this.getCollection(input.slug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(\"Failed to create collection\", \"CREATE_FAILED\");\n\t\t}\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Update a collection\n\t */\n\tasync updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection> {\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (!existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\tconst now = new Date().toISOString();\n\n\t\t// Derive hasSeo from supports array if supports is being updated and hasSeo not explicitly set\n\t\tconst supportsArray = input.supports ?? existing.supports;\n\t\tconst hasSeo =\n\t\t\tinput.hasSeo !== undefined\n\t\t\t\t? input.hasSeo\n\t\t\t\t: input.supports !== undefined\n\t\t\t\t\t? supportsArray.includes(\"seo\")\n\t\t\t\t\t: existing.hasSeo;\n\n\t\treturn withTransaction(this.db, async (trx) => {\n\t\t\tawait trx\n\t\t\t\t.updateTable(\"_emdash_collections\")\n\t\t\t\t.set({\n\t\t\t\t\tlabel: input.label ?? existing.label,\n\t\t\t\t\tlabel_singular: input.labelSingular ?? existing.labelSingular ?? null,\n\t\t\t\t\tdescription: input.description ?? existing.description ?? null,\n\t\t\t\t\ticon: input.icon ?? existing.icon ?? null,\n\t\t\t\t\tsupports: input.supports\n\t\t\t\t\t\t? JSON.stringify(input.supports)\n\t\t\t\t\t\t: JSON.stringify(existing.supports),\n\t\t\t\t\turl_pattern:\n\t\t\t\t\t\tinput.urlPattern !== undefined\n\t\t\t\t\t\t\t? (input.urlPattern ?? null)\n\t\t\t\t\t\t\t: (existing.urlPattern ?? null),\n\t\t\t\t\thas_seo: hasSeo ? 1 : 0,\n\t\t\t\t\tcomments_enabled:\n\t\t\t\t\t\tinput.commentsEnabled !== undefined\n\t\t\t\t\t\t\t? input.commentsEnabled\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t\t: existing.commentsEnabled\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0,\n\t\t\t\t\tcomments_moderation: input.commentsModeration ?? existing.commentsModeration,\n\t\t\t\t\tcomments_closed_after_days:\n\t\t\t\t\t\tinput.commentsClosedAfterDays !== undefined\n\t\t\t\t\t\t\t? input.commentsClosedAfterDays\n\t\t\t\t\t\t\t: existing.commentsClosedAfterDays,\n\t\t\t\t\tcomments_auto_approve_users:\n\t\t\t\t\t\tinput.commentsAutoApproveUsers !== undefined\n\t\t\t\t\t\t\t? input.commentsAutoApproveUsers\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t\t: existing.commentsAutoApproveUsers\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0,\n\t\t\t\t\tupdated_at: now,\n\t\t\t\t})\n\t\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t\t.execute();\n\n\t\t\tconst row = await trx\n\t\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t\t.selectAll()\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tif (!row) {\n\t\t\t\tthrow new SchemaError(\"Failed to update collection\", \"UPDATE_FAILED\");\n\t\t\t}\n\n\t\t\t// Sync FTS state when the supports array changes (e.g. search toggled on/off)\n\t\t\tif (input.supports !== undefined) {\n\t\t\t\tconst hadSearch = existing.supports.includes(\"search\");\n\t\t\t\tconst hasSearch = parseSupports(row.supports).includes(\"search\");\n\t\t\t\tif (hadSearch !== hasSearch) {\n\t\t\t\t\tawait this.syncSearchState(slug, trx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.mapCollectionRow(row);\n\t\t});\n\t}\n\n\t/**\n\t * Delete a collection\n\t */\n\tasync deleteCollection(slug: string, options?: { force?: boolean }): Promise<void> {\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (!existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Check if collection has content\n\t\tif (!options?.force) {\n\t\t\tconst hasContent = await this.collectionHasContent(slug);\n\t\t\tif (hasContent) {\n\t\t\t\tthrow new SchemaError(\n\t\t\t\t\t`Collection \"${slug}\" has content. Use force: true to delete.`,\n\t\t\t\t\t\"COLLECTION_HAS_CONTENT\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\t// Drop FTS table and triggers before dropping the content table\n\t\t\tconst ftsManager = new FTSManager(trx);\n\t\t\tawait ftsManager.dropFtsTable(slug);\n\n\t\t\t// Drop the content table\n\t\t\tconst tableName = this.getTableName(slug);\n\t\t\tawait sql`DROP TABLE IF EXISTS ${sql.ref(tableName)}`.execute(trx);\n\n\t\t\t// Delete the collection record (fields will cascade)\n\t\t\tawait trx.deleteFrom(\"_emdash_collections\").where(\"id\", \"=\", existing.id).execute();\n\t\t});\n\t}\n\n\t// ============================================\n\t// Field Operations\n\t// ============================================\n\n\t/**\n\t * List fields for a collection\n\t */\n\tasync listFields(collectionId: string): Promise<Field[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collectionId)\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t\t.orderBy(\"created_at\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map(this.mapFieldRow);\n\t}\n\n\t/**\n\t * Get a field by slug within a collection\n\t */\n\tasync getField(collectionSlug: string, fieldSlug: string): Promise<Field | null> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) return null;\n\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.where(\"slug\", \"=\", fieldSlug)\n\t\t\t.selectAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.mapFieldRow(row) : null;\n\t}\n\n\t/**\n\t * Create a new field\n\t */\n\tasync createField(collectionSlug: string, input: CreateFieldInput): Promise<Field> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(`Collection \"${collectionSlug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Validate slug\n\t\tthis.validateSlug(input.slug, \"field\");\n\t\tif (RESERVED_FIELD_SLUGS.includes(input.slug)) {\n\t\t\tthrow new SchemaError(`Field slug \"${input.slug}\" is reserved`, \"RESERVED_SLUG\");\n\t\t}\n\n\t\t// Check if field already exists\n\t\tconst existing = await this.getField(collectionSlug, input.slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${input.slug}\" already exists in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_EXISTS\",\n\t\t\t);\n\t\t}\n\n\t\tconst id = ulid();\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[input.type];\n\n\t\t// Get max sort order\n\t\tconst maxSort = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.select((eb) => eb.fn.max<number>(\"sort_order\").as(\"max\"))\n\t\t\t.executeTakeFirst();\n\n\t\tconst sortOrder = input.sortOrder ?? (maxSort?.max ?? -1) + 1;\n\n\t\treturn withTransaction(this.db, async (trx) => {\n\t\t\t// Insert field record\n\t\t\tawait trx\n\t\t\t\t.insertInto(\"_emdash_fields\")\n\t\t\t\t.values({\n\t\t\t\t\tid,\n\t\t\t\t\tcollection_id: collection.id,\n\t\t\t\t\tslug: input.slug,\n\t\t\t\t\tlabel: input.label,\n\t\t\t\t\ttype: input.type,\n\t\t\t\t\tcolumn_type: columnType,\n\t\t\t\t\trequired: input.required ? 1 : 0,\n\t\t\t\t\tunique: input.unique ? 1 : 0,\n\t\t\t\t\tdefault_value:\n\t\t\t\t\t\tinput.defaultValue !== undefined ? JSON.stringify(input.defaultValue) : null,\n\t\t\t\t\tvalidation: input.validation ? JSON.stringify(input.validation) : null,\n\t\t\t\t\twidget: input.widget ?? null,\n\t\t\t\t\toptions: input.options ? JSON.stringify(input.options) : null,\n\t\t\t\t\tsort_order: sortOrder,\n\t\t\t\t\tsearchable: input.searchable ? 1 : 0,\n\t\t\t\t\ttranslatable: input.translatable === false ? 0 : 1,\n\t\t\t\t})\n\t\t\t\t.execute();\n\n\t\t\t// Add column to content table — pass trx to stay on the same connection\n\t\t\tawait this.addColumn(\n\t\t\t\tcollectionSlug,\n\t\t\t\tinput.slug,\n\t\t\t\tinput.type,\n\t\t\t\t{\n\t\t\t\t\trequired: input.required,\n\t\t\t\t\tdefaultValue: input.defaultValue,\n\t\t\t\t},\n\t\t\t\ttrx,\n\t\t\t);\n\n\t\t\t// Read the created field via trx (not this.db) to avoid connection mutex deadlock\n\t\t\tconst fieldRow = await trx\n\t\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t\t.where(\"slug\", \"=\", input.slug)\n\t\t\t\t.selectAll()\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tif (!fieldRow) {\n\t\t\t\tthrow new SchemaError(\"Failed to create field\", \"CREATE_FAILED\");\n\t\t\t}\n\n\t\t\tconst field = this.mapFieldRow(fieldRow);\n\n\t\t\t// Sync search state if this field is searchable; support checks are handled by syncSearchState()\n\t\t\tif (input.searchable) {\n\t\t\t\tawait this.syncSearchState(collectionSlug, trx);\n\t\t\t}\n\n\t\t\treturn field;\n\t\t});\n\t}\n\n\t/**\n\t * Update a field\n\t */\n\tasync updateField(\n\t\tcollectionSlug: string,\n\t\tfieldSlug: string,\n\t\tinput: UpdateFieldInput,\n\t): Promise<Field> {\n\t\tconst field = await this.getField(collectionSlug, fieldSlug);\n\t\tif (!field) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${fieldSlug}\" not found in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_NOT_FOUND\",\n\t\t\t);\n\t\t}\n\n\t\t// `input.validation === undefined` means \"no change\" (keep existing);\n\t\t// an explicit `null` clears the column.\n\t\tconst nextValidation = input.validation === undefined ? field.validation : input.validation;\n\n\t\t// A field-type change is only safe when the underlying column type stays\n\t\t// the same. There is no in-place column migration (only addColumn/\n\t\t// dropColumn), so a change that would alter the SQLite column affinity\n\t\t// (e.g. `text` TEXT -> `portableText` JSON) is rejected rather than\n\t\t// silently rewriting only the metadata — which would leave `column_type`\n\t\t// pointing at a column type the real `ec_*` column doesn't have (#1397).\n\t\tlet nextType = field.type;\n\t\tlet nextColumnType = field.columnType;\n\t\tif (input.type !== undefined && input.type !== field.type) {\n\t\t\tconst newColumnType = FIELD_TYPE_TO_COLUMN[input.type];\n\t\t\tif (newColumnType !== field.columnType) {\n\t\t\t\tthrow new SchemaError(\n\t\t\t\t\t`Cannot change field \"${fieldSlug}\" in collection \"${collectionSlug}\" from type ` +\n\t\t\t\t\t\t`\"${field.type}\" to \"${input.type}\": the underlying column type would change from ` +\n\t\t\t\t\t\t`${field.columnType} to ${newColumnType}, which requires a manual content migration. ` +\n\t\t\t\t\t\t`Drop and re-create the field, or migrate the column data, before changing its type.`,\n\t\t\t\t\t\"FIELD_TYPE_COLUMN_CHANGE\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tnextType = input.type;\n\t\t\tnextColumnType = newColumnType;\n\t\t}\n\n\t\treturn withTransaction(this.db, async (trx) => {\n\t\t\tawait trx\n\t\t\t\t.updateTable(\"_emdash_fields\")\n\t\t\t\t.set({\n\t\t\t\t\ttype: nextType,\n\t\t\t\t\tcolumn_type: nextColumnType,\n\t\t\t\t\tlabel: input.label ?? field.label,\n\t\t\t\t\trequired:\n\t\t\t\t\t\tinput.required !== undefined ? (input.required ? 1 : 0) : field.required ? 1 : 0,\n\t\t\t\t\tunique: input.unique !== undefined ? (input.unique ? 1 : 0) : field.unique ? 1 : 0,\n\t\t\t\t\tsearchable:\n\t\t\t\t\t\tinput.searchable !== undefined ? (input.searchable ? 1 : 0) : field.searchable ? 1 : 0,\n\t\t\t\t\ttranslatable:\n\t\t\t\t\t\tinput.translatable !== undefined\n\t\t\t\t\t\t\t? input.translatable\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t\t: field.translatable\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: 0,\n\t\t\t\t\tdefault_value:\n\t\t\t\t\t\tinput.defaultValue !== undefined\n\t\t\t\t\t\t\t? JSON.stringify(input.defaultValue)\n\t\t\t\t\t\t\t: field.defaultValue !== undefined\n\t\t\t\t\t\t\t\t? JSON.stringify(field.defaultValue)\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\tvalidation: nextValidation ? JSON.stringify(nextValidation) : null,\n\t\t\t\t\twidget: input.widget ?? field.widget ?? null,\n\t\t\t\t\toptions: input.options\n\t\t\t\t\t\t? JSON.stringify(input.options)\n\t\t\t\t\t\t: field.options\n\t\t\t\t\t\t\t? JSON.stringify(field.options)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tsort_order: input.sortOrder ?? field.sortOrder,\n\t\t\t\t})\n\t\t\t\t.where(\"id\", \"=\", field.id)\n\t\t\t\t.execute();\n\n\t\t\t// Read the updated field via trx (not this.db) to avoid connection mutex deadlock\n\t\t\tconst updatedRow = await trx\n\t\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t\t.where(\"collection_id\", \"=\", field.collectionId)\n\t\t\t\t.where(\"slug\", \"=\", fieldSlug)\n\t\t\t\t.selectAll()\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tif (!updatedRow) {\n\t\t\t\tthrow new SchemaError(\"Failed to update field\", \"UPDATE_FAILED\");\n\t\t\t}\n\n\t\t\tconst updated = this.mapFieldRow(updatedRow);\n\n\t\t\t// If searchable changed, sync FTS state for this collection\n\t\t\tconst searchableChanged =\n\t\t\t\tinput.searchable !== undefined && input.searchable !== field.searchable;\n\t\t\tif (searchableChanged) {\n\t\t\t\tawait this.syncSearchState(collectionSlug, trx);\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t}\n\n\t/**\n\t * Synchronize an existing FTS index with the collection's current state.\n\t *\n\t * Only rebuilds or disables — never first-time enables. First-time FTS\n\t * enablement is handled by the seed's explicit enableSearch call (which\n\t * is try-caught) or the admin UI toggle.\n\t *\n\t * - FTS active + still has search support and searchable fields → rebuild\n\t * - FTS active + lost search support or no searchable fields → disable\n\t * - FTS not active → no-op\n\t *\n\t * Pass `db` when calling from within a transaction so FTS operations\n\t * participate in the same transaction and are rolled back on failure.\n\t */\n\tprivate async syncSearchState(collectionSlug: string, db?: Kysely<Database>): Promise<void> {\n\t\tconst conn = db ?? this.db;\n\t\tconst ftsManager = new FTSManager(conn);\n\n\t\t// Query via conn (not this.db) to avoid connection mutex deadlock when called inside a transaction\n\t\tconst row = await conn\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.select(\"supports\")\n\t\t\t.executeTakeFirst();\n\t\tif (!row) return;\n\n\t\tconst wantsSearch = parseSupports(row.supports).includes(\"search\");\n\t\tconst searchableFields = await ftsManager.getSearchableFields(collectionSlug);\n\t\tconst config = await ftsManager.getSearchConfig(collectionSlug);\n\t\tconst ftsActive = config?.enabled === true;\n\n\t\tif (wantsSearch && searchableFields.length > 0 && ftsActive) {\n\t\t\tawait ftsManager.rebuildIndex(collectionSlug, searchableFields, config?.weights);\n\t\t} else if (ftsActive && (!wantsSearch || searchableFields.length === 0)) {\n\t\t\tawait ftsManager.disableSearch(collectionSlug);\n\t\t}\n\t}\n\n\t/**\n\t * Delete a field\n\t */\n\tasync deleteField(collectionSlug: string, fieldSlug: string): Promise<void> {\n\t\tconst field = await this.getField(collectionSlug, fieldSlug);\n\t\tif (!field) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${fieldSlug}\" not found in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_NOT_FOUND\",\n\t\t\t);\n\t\t}\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\t// Delete the field record first so syncSearchState sees the updated field list.\n\t\t\t// This ordering matters for searchable fields: SQLite prevents dropping a column\n\t\t\t// that is still referenced by a trigger. syncSearchState drops and recreates the\n\t\t\t// FTS triggers based on the remaining searchable fields, clearing the dependency\n\t\t\t// before we attempt the ALTER TABLE DROP COLUMN below.\n\t\t\tawait trx.deleteFrom(\"_emdash_fields\").where(\"id\", \"=\", field.id).execute();\n\n\t\t\t// If the deleted field was searchable, sync FTS state (removes old triggers)\n\t\t\tif (field.searchable) {\n\t\t\t\tawait this.syncSearchState(collectionSlug, trx);\n\t\t\t}\n\n\t\t\t// Drop column from content table — safe now because FTS triggers are gone\n\t\t\tawait this.dropColumn(collectionSlug, fieldSlug, trx);\n\t\t});\n\t}\n\n\t/**\n\t * Reorder fields\n\t */\n\tasync reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(`Collection \"${collectionSlug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Update sort_order for each field\n\t\tfor (let i = 0; i < fieldSlugs.length; i++) {\n\t\t\tawait this.db\n\t\t\t\t.updateTable(\"_emdash_fields\")\n\t\t\t\t.set({ sort_order: i })\n\t\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t\t.where(\"slug\", \"=\", fieldSlugs[i])\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\t// ============================================\n\t// DDL Operations\n\t// ============================================\n\n\t/**\n\t * Create a content table for a collection\n\t */\n\tprivate async createContentTable(slug: string, db?: Kysely<Database>): Promise<void> {\n\t\tconst conn = db ?? this.db;\n\t\tconst tableName = this.getTableName(slug);\n\n\t\tawait conn.schema\n\t\t\t.createTable(tableName)\n\t\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t\t.addColumn(\"slug\", \"text\")\n\t\t\t.addColumn(\"status\", \"text\", (col) => col.defaultTo(\"draft\"))\n\t\t\t.addColumn(\"author_id\", \"text\")\n\t\t\t.addColumn(\"primary_byline_id\", \"text\")\n\t\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(conn)))\n\t\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(conn)))\n\t\t\t.addColumn(\"published_at\", \"text\")\n\t\t\t.addColumn(\"scheduled_at\", \"text\")\n\t\t\t.addColumn(\"deleted_at\", \"text\")\n\t\t\t.addColumn(\"version\", \"integer\", (col) => col.defaultTo(1))\n\t\t\t.addColumn(\"live_revision_id\", \"text\", (col) => col.references(\"revisions.id\"))\n\t\t\t.addColumn(\"draft_revision_id\", \"text\", (col) => col.references(\"revisions.id\"))\n\t\t\t.addColumn(\"locale\", \"text\", (col) => col.notNull().defaultTo(\"en\"))\n\t\t\t.addColumn(\"translation_group\", \"text\")\n\t\t\t.addUniqueConstraint(`${tableName}_slug_locale_unique`, [\"slug\", \"locale\"])\n\t\t\t.execute();\n\n\t\t// Create standard indexes\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_slug`)}\n\t\t\tON ${sql.ref(tableName)} (slug)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_scheduled`)}\n\t\t\tON ${sql.ref(tableName)} (scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_live_revision`)}\n\t\t\tON ${sql.ref(tableName)} (live_revision_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_draft_revision`)}\n\t\t\tON ${sql.ref(tableName)} (draft_revision_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_author`)}\n\t\t\tON ${sql.ref(tableName)} (author_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_primary_byline`)}\n\t\t\tON ${sql.ref(tableName)} (primary_byline_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_locale`)}\n\t\t\tON ${sql.ref(tableName)} (locale)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_translation_group`)}\n\t\t\tON ${sql.ref(tableName)} (translation_group)\n\t\t`.execute(conn);\n\n\t\t// Composite indexes for optimized query performance (see migration 033)\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_updated_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, updated_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_status`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, status)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_created_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, created_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_published_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, published_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\t// Locale-aware composite indexes for i18n content lists (see migration 041).\n\t\t// Short `loc_upd`/`loc_crt` suffix keeps the updated/created discriminator\n\t\t// inside Postgres's 63-byte identifier limit for long slugs; keep these\n\t\t// names identical to migration 041.\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_loc_upd`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, locale, updated_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_loc_crt`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, locale, created_at DESC, id DESC)\n\t\t`.execute(conn);\n\t}\n\n\t/**\n\t * Add a column to a content table\n\t */\n\tprivate async addColumn(\n\t\tcollectionSlug: string,\n\t\tfieldSlug: string,\n\t\tfieldType: FieldType,\n\t\toptions?: { required?: boolean; defaultValue?: unknown },\n\t\tdb?: Kysely<Database>,\n\t): Promise<void> {\n\t\tconst conn = db ?? this.db;\n\t\tconst tableName = this.getTableName(collectionSlug);\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\t\tconst columnName = this.getColumnName(fieldSlug);\n\n\t\t// Build ALTER TABLE statement\n\t\t// Note: SQLite requires DEFAULT for NOT NULL columns in ALTER TABLE\n\t\tif (options?.required && options?.defaultValue !== undefined) {\n\t\t\tconst defaultVal = this.formatDefaultValue(options.defaultValue, fieldType);\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)} NOT NULL DEFAULT ${sql.raw(defaultVal)}\n\t\t\t`.execute(conn);\n\t\t} else if (options?.required) {\n\t\t\t// For required fields without default, use empty string/0 as default\n\t\t\tconst defaultVal = this.getEmptyDefault(fieldType);\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)} NOT NULL DEFAULT ${sql.raw(defaultVal)}\n\t\t\t`.execute(conn);\n\t\t} else {\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)}\n\t\t\t`.execute(conn);\n\t\t}\n\t}\n\n\t/**\n\t * Drop a column from a content table\n\t */\n\tprivate async dropColumn(\n\t\tcollectionSlug: string,\n\t\tfieldSlug: string,\n\t\tdb?: Kysely<Database>,\n\t): Promise<void> {\n\t\tconst tableName = this.getTableName(collectionSlug);\n\t\tconst columnName = this.getColumnName(fieldSlug);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tDROP COLUMN ${sql.ref(columnName)}\n\t\t`.execute(db ?? this.db);\n\t}\n\n\t// ============================================\n\t// Helpers\n\t// ============================================\n\n\t/**\n\t * Check if a collection has any content\n\t */\n\tprivate async collectionHasContent(slug: string): Promise<boolean> {\n\t\tconst tableName = this.getTableName(slug);\n\t\ttry {\n\t\t\tconst result = await sql<{ count: number }>`\n\t\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(tableName)}\n\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t`.execute(this.db);\n\t\t\treturn (result.rows[0]?.count ?? 0) > 0;\n\t\t} catch {\n\t\t\t// Table might not exist\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get table name for a collection\n\t */\n\tprivate getTableName(slug: string): string {\n\t\tvalidateIdentifier(slug, \"collection slug\");\n\t\treturn `ec_${slug}`;\n\t}\n\n\t/**\n\t * Get column name for a field\n\t */\n\tprivate getColumnName(slug: string): string {\n\t\tvalidateIdentifier(slug, \"field slug\");\n\t\treturn slug;\n\t}\n\n\t/**\n\t * Validate a slug\n\t */\n\tprivate validateSlug(slug: string, type: \"collection\" | \"field\"): void {\n\t\tif (!slug || typeof slug !== \"string\") {\n\t\t\tthrow new SchemaError(`${type} slug is required`, \"INVALID_SLUG\");\n\t\t}\n\n\t\tif (!SLUG_VALIDATION_PATTERN.test(slug)) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`${type} slug must start with a letter and contain only lowercase letters, numbers, and underscores`,\n\t\t\t\t\"INVALID_SLUG\",\n\t\t\t);\n\t\t}\n\n\t\tif (slug.length > 63) {\n\t\t\tthrow new SchemaError(`${type} slug must be 63 characters or less`, \"INVALID_SLUG\");\n\t\t}\n\t}\n\n\t/**\n\t * Format a default value for SQL.\n\t *\n\t * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant\n\t * expression — parameterized values cannot be used here. We manually escape\n\t * single quotes and coerce types to ensure the output is safe.\n\t *\n\t * INTEGER/REAL values are coerced through `Number()` which can only produce\n\t * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.\n\t * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).\n\t */\n\tprivate formatDefaultValue(value: unknown, fieldType: FieldType): string {\n\t\tif (value === null || value === undefined) {\n\t\t\treturn \"NULL\";\n\t\t}\n\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\n\t\tif (columnType === \"JSON\") {\n\t\t\t// JSON.stringify produces valid JSON; escape single quotes for SQL literal\n\t\t\tconst json = JSON.stringify(value);\n\t\t\treturn `'${json.replace(SINGLE_QUOTE_PATTERN, \"''\")}'`;\n\t\t}\n\n\t\tif (columnType === \"INTEGER\") {\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\treturn value ? \"1\" : \"0\";\n\t\t\t}\n\t\t\tconst num = Number(value);\n\t\t\tif (!Number.isFinite(num)) {\n\t\t\t\treturn \"0\";\n\t\t\t}\n\t\t\treturn String(Math.trunc(num));\n\t\t}\n\n\t\tif (columnType === \"REAL\") {\n\t\t\tconst num = Number(value);\n\t\t\tif (!Number.isFinite(num)) {\n\t\t\t\treturn \"0\";\n\t\t\t}\n\t\t\treturn String(num);\n\t\t}\n\n\t\t// TEXT — escape single quotes via SQL standard doubling\n\t\tlet text: string;\n\t\tif (typeof value === \"string\") {\n\t\t\ttext = value;\n\t\t} else if (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\ttext = String(value);\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\ttext = JSON.stringify(value);\n\t\t} else {\n\t\t\ttext = \"\";\n\t\t}\n\t\treturn `'${text.replace(SINGLE_QUOTE_PATTERN, \"''\")}'`;\n\t}\n\n\t/**\n\t * Get empty default for a field type\n\t */\n\tprivate getEmptyDefault(fieldType: FieldType): string {\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\n\t\tswitch (columnType) {\n\t\t\tcase \"INTEGER\":\n\t\t\t\treturn \"0\";\n\t\t\tcase \"REAL\":\n\t\t\t\treturn \"0.0\";\n\t\t\tcase \"JSON\":\n\t\t\t\treturn \"'null'\";\n\t\t\tdefault:\n\t\t\t\treturn \"''\";\n\t\t}\n\t}\n\n\t/**\n\t * Map a collection row to a Collection object\n\t */\n\tprivate mapCollectionRow = (row: Selectable<CollectionTable>): Collection => {\n\t\tconst moderation = row.comments_moderation;\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\tlabelSingular: row.label_singular ?? undefined,\n\t\t\tdescription: row.description ?? undefined,\n\t\t\ticon: row.icon ?? undefined,\n\t\t\tsupports: parseSupports(row.supports),\n\t\t\tsource: row.source && isCollectionSource(row.source) ? row.source : undefined,\n\t\t\thasSeo: row.has_seo === 1,\n\t\t\turlPattern: row.url_pattern ?? undefined,\n\t\t\tcommentsEnabled: row.comments_enabled === 1,\n\t\t\tcommentsModeration:\n\t\t\t\tmoderation === \"all\" || moderation === \"first_time\" || moderation === \"none\"\n\t\t\t\t\t? moderation\n\t\t\t\t\t: \"first_time\",\n\t\t\tcommentsClosedAfterDays: row.comments_closed_after_days ?? 90,\n\t\t\tcommentsAutoApproveUsers: row.comments_auto_approve_users === 1,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tupdatedAt: row.updated_at,\n\t\t};\n\t};\n\n\t/**\n\t * Map a field row to a Field object\n\t */\n\tprivate mapFieldRow = (row: Selectable<FieldTable>): Field => {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tcollectionId: row.collection_id,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\ttype: isFieldType(row.type) ? row.type : \"string\",\n\t\t\tcolumnType: isColumnType(row.column_type) ? row.column_type : \"TEXT\",\n\t\t\trequired: row.required === 1,\n\t\t\tunique: row.unique === 1,\n\t\t\tdefaultValue: row.default_value ? JSON.parse(row.default_value) : undefined,\n\t\t\tvalidation: row.validation ? JSON.parse(row.validation) : undefined,\n\t\t\twidget: row.widget ?? undefined,\n\t\t\toptions: row.options ? JSON.parse(row.options) : undefined,\n\t\t\tsortOrder: row.sort_order,\n\t\t\tsearchable: row.searchable === 1,\n\t\t\ttranslatable: row.translatable !== 0,\n\t\t\tcreatedAt: row.created_at,\n\t\t};\n\t};\n\n\t// ============================================\n\t// Discovery\n\t// ============================================\n\n\t/**\n\t * Discover orphaned content tables\n\t *\n\t * Finds ec_* tables that exist in the database but don't have a\n\t * corresponding entry in _emdash_collections.\n\t */\n\tasync discoverOrphanedTables(): Promise<\n\t\tArray<{ slug: string; tableName: string; rowCount: number }>\n\t> {\n\t\t// Get all ec_* tables\n\t\t// Content tables are ec_* (e.g., ec_posts, ec_pages)\n\t\t// Internal tables are _emdash_* (e.g., _emdash_collections, _emdash_fts_posts)\n\t\tconst allTables = await listTablesLike(this.db, \"ec_%\");\n\n\t\t// Get registered collections\n\t\tconst registered = await this.listCollections();\n\t\tconst registeredSlugs = new Set(registered.map((c) => c.slug));\n\n\t\t// Find orphans\n\t\tconst orphans: Array<{\n\t\t\tslug: string;\n\t\t\ttableName: string;\n\t\t\trowCount: number;\n\t\t}> = [];\n\n\t\tfor (const tableName of allTables) {\n\t\t\tconst slug = tableName.replace(EC_PREFIX_PATTERN, \"\");\n\n\t\t\tif (!registeredSlugs.has(slug)) {\n\t\t\t\t// Count rows in the orphaned table\n\t\t\t\ttry {\n\t\t\t\t\tconst countResult = await sql<{ count: number }>`\n\t\t\t\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t`.execute(this.db);\n\n\t\t\t\t\torphans.push({\n\t\t\t\t\t\tslug,\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\trowCount: countResult.rows[0]?.count ?? 0,\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\t// Table might have unexpected schema, still report it\n\t\t\t\t\torphans.push({\n\t\t\t\t\t\tslug,\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\trowCount: 0,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn orphans;\n\t}\n\n\t/**\n\t * Register an orphaned table as a collection\n\t *\n\t * Creates a _emdash_collections entry for an existing ec_* table.\n\t */\n\tasync registerOrphanedTable(\n\t\tslug: string,\n\t\toptions?: {\n\t\t\tlabel?: string;\n\t\t\tlabelSingular?: string;\n\t\t\tdescription?: string;\n\t\t},\n\t): Promise<Collection> {\n\t\t// Verify table exists\n\t\tconst tableName = this.getTableName(slug);\n\t\tconst exists = await tableExists(this.db, tableName);\n\n\t\tif (!exists) {\n\t\t\tthrow new SchemaError(`Table \"${tableName}\" does not exist`, \"TABLE_NOT_FOUND\");\n\t\t}\n\n\t\t// Check if already registered\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" is already registered`, \"COLLECTION_EXISTS\");\n\t\t}\n\n\t\t// Create collection entry\n\t\tconst id = ulid();\n\t\tconst label = options?.label || this.slugToLabel(slug);\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_collections\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug,\n\t\t\t\tlabel,\n\t\t\t\tlabel_singular: options?.labelSingular ?? null,\n\t\t\t\tdescription: options?.description ?? null,\n\t\t\t\ticon: null,\n\t\t\t\tsupports: JSON.stringify([]),\n\t\t\t\tsource: \"discovered\",\n\t\t\t\thas_seo: 0,\n\t\t\t\turl_pattern: null,\n\t\t\t})\n\t\t\t.execute();\n\n\t\tconst collection = await this.getCollection(slug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(\"Failed to register orphaned table\", \"REGISTER_FAILED\");\n\t\t}\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Convert slug to human-readable label\n\t */\n\tprivate slugToLabel(slug: string): string {\n\t\treturn slug\n\t\t\t.replace(UNDERSCORE_PATTERN, \" \")\n\t\t\t.replace(WORD_BOUNDARY_PATTERN, (c) => c.toUpperCase());\n\t}\n}\n"],"mappings":"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"}
|