emdash 0.35.0 → 0.37.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/activation-K0kGBWuJ.mjs +382 -0
- package/dist/activation-K0kGBWuJ.mjs.map +1 -0
- package/dist/{adapters-Bb1vG41D.d.mts → adapters-BDQwg236.d.mts} +6 -4
- package/dist/{adapters-Bb1vG41D.d.mts.map → adapters-BDQwg236.d.mts.map} +1 -1
- package/dist/{allowed-origins-DW7sYyqg.mjs → allowed-origins-BGglilcs.mjs} +2 -2
- package/dist/{allowed-origins-DW7sYyqg.mjs.map → allowed-origins-BGglilcs.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +23 -21
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/api-Dz6rgoa3.mjs +10040 -0
- package/dist/api-Dz6rgoa3.mjs.map +1 -0
- package/dist/{api-tokens-KO24G1Fd.mjs → api-tokens-BSsQACNe.mjs} +2 -2
- package/dist/{api-tokens-KO24G1Fd.mjs.map → api-tokens-BSsQACNe.mjs.map} +1 -1
- package/dist/{apply-kUDt80-G.mjs → apply-B4SIOxR1.mjs} +34 -35
- package/dist/{apply-kUDt80-G.mjs.map → apply-B4SIOxR1.mjs.map} +1 -1
- package/dist/astro/image-endpoint.mjs +2 -2
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +128 -44
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +10 -7
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/media-usage-write-fence.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +4 -4
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +11 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +237 -1412
- 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 +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -13
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- 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/media-usage/activation.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/activation.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +46 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +44 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -11
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +53 -47
- 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 +54 -48
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +60 -50
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +179 -139
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +61 -51
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +93 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +53 -47
- 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 +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +53 -47
- 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 +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
- 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 +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/me.mjs +19 -9
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +14 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +13 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +17 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +17 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
- 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 +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +17 -17
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +13 -13
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +12 -10
- 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 +17 -17
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +27 -27
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +188 -65
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
- package/dist/astro/routes/api/media/_id_/replace.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/replace.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs +91 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +18 -13
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +21 -13
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -2
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
- package/dist/astro/routes/api/media/folders/_id_.d.mts +10 -0
- package/dist/astro/routes/api/media/folders/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs +52 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/media/folders/index.d.mts +9 -0
- package/dist/astro/routes/api/media/folders/index.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/index.mjs +41 -0
- package/dist/astro/routes/api/media/folders/index.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +16 -14
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +59 -27
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +20 -13
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +16 -12
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +21 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -11
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +253 -40
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
- package/dist/astro/routes/api/redirects/index.mjs +11 -11
- package/dist/astro/routes/api/relations/_id_/index.mjs +17 -15
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +12 -10
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +17 -15
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +53 -47
- 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 +53 -47
- 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 +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +10 -8
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +53 -47
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +53 -47
- 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 +5 -5
- 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/backups/archives/_name_.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +5 -5
- package/dist/astro/routes/api/settings/backups/export.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/index.mjs +7 -7
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings/email.mjs.map +1 -1
- package/dist/astro/routes/api/settings.d.mts.map +1 -1
- package/dist/astro/routes/api/settings.mjs +20 -16
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +11 -11
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +35 -28
- 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 +32 -30
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +7 -7
- package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +21 -17
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +25 -18
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +14 -14
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +26 -19
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -8
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +17 -13
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +8 -6
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +7 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +10 -10
- package/dist/astro/routes/sitemap.xml.mjs +8 -8
- package/dist/astro/types.d.mts +37 -17
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-DUElxgOQ.mjs → authorize-Bkf_UHhD.mjs} +2 -2
- package/dist/{authorize-DUElxgOQ.mjs.map → authorize-Bkf_UHhD.mjs.map} +1 -1
- package/dist/{backup-DWYpJlLj.mjs → backup-rwVAl9NI.mjs} +5 -5
- package/dist/{backup-DWYpJlLj.mjs.map → backup-rwVAl9NI.mjs.map} +1 -1
- package/dist/{bundle-vn56sLos.mjs → bundle-C8S2Zl6U.mjs} +4 -4
- package/dist/{bundle-vn56sLos.mjs.map → bundle-C8S2Zl6U.mjs.map} +1 -1
- package/dist/{byline-yjvWq4ip.mjs → byline-DuhF7NWl.mjs} +27 -14
- package/dist/byline-DuhF7NWl.mjs.map +1 -0
- package/dist/{byline-fields-txaLGoME.mjs → byline-fields-BovY4KYM.mjs} +2 -2
- package/dist/{byline-fields-txaLGoME.mjs.map → byline-fields-BovY4KYM.mjs.map} +1 -1
- package/dist/{byline-registry-DDun8sxh.mjs → byline-registry-Bpu9-MVs.mjs} +2 -2
- package/dist/{byline-registry-DDun8sxh.mjs.map → byline-registry-Bpu9-MVs.mjs.map} +1 -1
- package/dist/{bylines-DjXS5p0P.mjs → bylines-CJ5nd6Lw.mjs} +7 -7
- package/dist/{bylines-DjXS5p0P.mjs.map → bylines-CJ5nd6Lw.mjs.map} +1 -1
- package/dist/{bylines-Bu7pchQ4.mjs → bylines-RwBAeOF1.mjs} +3 -3
- package/dist/{bylines-Bu7pchQ4.mjs.map → bylines-RwBAeOF1.mjs.map} +1 -1
- package/dist/{cache-C46-3Irl.mjs → cache-BF5Kvn59.mjs} +4 -4
- package/dist/{cache-C46-3Irl.mjs.map → cache-BF5Kvn59.mjs.map} +1 -1
- package/dist/capture-triggers-CNW1q3HK.mjs +362 -0
- package/dist/capture-triggers-CNW1q3HK.mjs.map +1 -0
- package/dist/{challenge-store-SIL5DsF2.mjs → challenge-store-DQN_Yrck.mjs} +5 -3
- package/dist/challenge-store-DQN_Yrck.mjs.map +1 -0
- package/dist/chrome-tags-D8fiZG94.mjs +24 -0
- package/dist/chrome-tags-D8fiZG94.mjs.map +1 -0
- package/dist/{chunks-fiZ8G9RJ.mjs → chunks-C4szrD8o.mjs} +2 -2
- package/dist/{chunks-fiZ8G9RJ.mjs.map → chunks-C4szrD8o.mjs.map} +1 -1
- package/dist/cli/index.mjs +37 -53
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +74 -4
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +54 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/{collection-deletion-DQPvMD8R.mjs → collection-deletion-Bj07NHbj.mjs} +13 -356
- package/dist/collection-deletion-Bj07NHbj.mjs.map +1 -0
- package/dist/{comment-reaction-D-2J84UE.mjs → comment-reaction-BhrvSHml.mjs} +2 -2
- package/dist/{comment-reaction-D-2J84UE.mjs.map → comment-reaction-BhrvSHml.mjs.map} +1 -1
- package/dist/{comment-Dxlep6cE.mjs → comment-vxOzWbZN.mjs} +2 -2
- package/dist/{comment-Dxlep6cE.mjs.map → comment-vxOzWbZN.mjs.map} +1 -1
- package/dist/{comments-CTfZtLmM.mjs → comments-Ct4ensnf.mjs} +2 -2
- package/dist/{comments-CTfZtLmM.mjs.map → comments-Ct4ensnf.mjs.map} +1 -1
- package/dist/{components-CQy3lh9x.mjs → components-DJbo1z0S.mjs} +1 -1
- package/dist/{components-CQy3lh9x.mjs.map → components-DJbo1z0S.mjs.map} +1 -1
- package/dist/{config-COQzTe5Q.d.mts → config-B9eZ340f.d.mts} +1 -1
- package/dist/{config-COQzTe5Q.d.mts.map → config-B9eZ340f.d.mts.map} +1 -1
- package/dist/config-it29yDLA.mjs +1163 -0
- package/dist/config-it29yDLA.mjs.map +1 -0
- package/dist/{content-ZHCc1ngN.mjs → content-DjvM0T92.mjs} +86 -45
- package/dist/content-DjvM0T92.mjs.map +1 -0
- package/dist/{content-list-query-wJ2WN8Vp.d.mts → content-list-query-Btqd4uV2.d.mts} +1 -1
- package/dist/{content-list-query-wJ2WN8Vp.d.mts.map → content-list-query-Btqd4uV2.d.mts.map} +1 -1
- package/dist/{content-refresh-B_8SJzuU.mjs → content-refresh-Bwp-8yGy.mjs} +1139 -111
- package/dist/content-refresh-Bwp-8yGy.mjs.map +1 -0
- package/dist/{media-usage-BZCydfvu.mjs → content-repair-Czdp7jz5.mjs} +5 -196
- package/dist/content-repair-Czdp7jz5.mjs.map +1 -0
- package/dist/{context-ZldbZcle.mjs → context-CX6gxOLW.mjs} +55 -20
- package/dist/context-CX6gxOLW.mjs.map +1 -0
- package/dist/{cron-Y9aLtgrA.mjs → cron-C6o7VppJ.mjs} +1 -1
- package/dist/{cron-Y9aLtgrA.mjs.map → cron-C6o7VppJ.mjs.map} +1 -1
- package/dist/{dashboard-DvHbk_cv.mjs → dashboard-C2kTeeRI.mjs} +5 -5
- package/dist/{dashboard-DvHbk_cv.mjs.map → dashboard-C2kTeeRI.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +3 -3
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/postgres.d.mts.map +1 -1
- package/dist/db/postgres.mjs +19 -3
- package/dist/db/postgres.mjs.map +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +3 -3
- package/dist/db/sqlite.mjs.map +1 -1
- package/dist/{default-DdDl3fxv.mjs → default-Clra32mw.mjs} +1 -1
- package/dist/{default-DdDl3fxv.mjs.map → default-Clra32mw.mjs.map} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts → deferred-tasks-CvDETTJO.d.mts} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts.map → deferred-tasks-CvDETTJO.d.mts.map} +1 -1
- package/dist/dev-typegen-DzOPfsNj.mjs +29 -0
- package/dist/dev-typegen-DzOPfsNj.mjs.map +1 -0
- package/dist/{device-flow-C0GdD_z8.mjs → device-flow-D2oCWvLJ.mjs} +5 -5
- package/dist/{device-flow-C0GdD_z8.mjs.map → device-flow-D2oCWvLJ.mjs.map} +1 -1
- package/dist/{direct-executor-CDXeJCSs.mjs → direct-executor-Bfa5_ToE.mjs} +3 -3
- package/dist/{direct-executor-CDXeJCSs.mjs.map → direct-executor-Bfa5_ToE.mjs.map} +1 -1
- package/dist/{dist-D_6CKR8z.mjs → dist-89xCrGqi.mjs} +1 -1
- package/dist/{dist-D_6CKR8z.mjs.map → dist-89xCrGqi.mjs.map} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs → email-console-Dzb6uGYa.mjs} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs.map → email-console-Dzb6uGYa.mjs.map} +1 -1
- package/dist/{enrich-_ySMEvEE.mjs → enrich-BX0IDp4z.mjs} +3 -3
- package/dist/{enrich-_ySMEvEE.mjs.map → enrich-BX0IDp4z.mjs.map} +1 -1
- package/dist/{error-DupyJZE2.mjs → error-DFrQjppn.mjs} +2 -2
- package/dist/{error-DupyJZE2.mjs.map → error-DFrQjppn.mjs.map} +1 -1
- package/dist/{errors-CLUPm7aD.mjs → errors-DsVoDUjJ.mjs} +24 -2
- package/dist/errors-DsVoDUjJ.mjs.map +1 -0
- package/dist/{escape-DUY2r2Zs.mjs → escape-HmHTC1Is.mjs} +1 -1
- package/dist/{escape-DUY2r2Zs.mjs.map → escape-HmHTC1Is.mjs.map} +1 -1
- package/dist/{field-defs-cache-BzwBlJrR.mjs → field-defs-cache-BM4SIRqH.mjs} +5 -5
- package/dist/{field-defs-cache-BzwBlJrR.mjs.map → field-defs-cache-BM4SIRqH.mjs.map} +1 -1
- package/dist/focal-point-BeWFo6Xx.mjs +23 -0
- package/dist/focal-point-BeWFo6Xx.mjs.map +1 -0
- package/dist/{fts-manager-DyZEohZC.mjs → fts-manager-Do1BlW2r.mjs} +3 -3
- package/dist/{fts-manager-DyZEohZC.mjs.map → fts-manager-Do1BlW2r.mjs.map} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs → hash-3JJPlHF2.mjs} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs.map → hash-3JJPlHF2.mjs.map} +1 -1
- package/dist/hook-result-DCh2WUpe.d.mts +31 -0
- package/dist/hook-result-DCh2WUpe.d.mts.map +1 -0
- package/dist/{hreflang-DwT2E0Sa.d.mts → hreflang-B6hbAuuO.d.mts} +2 -2
- package/dist/{hreflang-DwT2E0Sa.d.mts.map → hreflang-B6hbAuuO.d.mts.map} +1 -1
- package/dist/{hreflang-BBe83kKa.mjs → hreflang-DQbPZliA.mjs} +7 -7
- package/dist/{hreflang-BBe83kKa.mjs.map → hreflang-DQbPZliA.mjs.map} +1 -1
- package/dist/{identity-Ys6Dlc9C.mjs → identity-DksvEazf.mjs} +3 -3
- package/dist/{identity-Ys6Dlc9C.mjs.map → identity-DksvEazf.mjs.map} +1 -1
- package/dist/{import-DPkLmeXO.mjs → import-CJpaBBBT.mjs} +6 -6
- package/dist/{import-DPkLmeXO.mjs.map → import-CJpaBBBT.mjs.map} +1 -1
- package/dist/{index-BVBZj4-7.d.mts → index-BJNMCWmu.d.mts} +267 -82
- package/dist/index-BJNMCWmu.d.mts.map +1 -0
- package/dist/{index-C9KuQyO-.d.mts → index-Du8K7bWa.d.mts} +3 -3
- package/dist/{index-C9KuQyO-.d.mts.map → index-Du8K7bWa.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +79 -73
- package/dist/{init-lock-6b309ZrF.mjs → init-lock-DJkX6Hto.mjs} +1 -1
- package/dist/{init-lock-6b309ZrF.mjs.map → init-lock-DJkX6Hto.mjs.map} +1 -1
- package/dist/{load-YJ2xl3ra.mjs → load-CawHjTOH.mjs} +2 -2
- package/dist/{load-YJ2xl3ra.mjs.map → load-CawHjTOH.mjs.map} +1 -1
- package/dist/{loader-CdG_Ci3H.mjs → loader-Z8vl7zTq.mjs} +48 -13
- package/dist/loader-Z8vl7zTq.mjs.map +1 -0
- package/dist/{manifest-builder-B252yQUf.mjs → manifest-builder-COtzuca2.mjs} +2 -2
- package/dist/{manifest-builder-B252yQUf.mjs.map → manifest-builder-COtzuca2.mjs.map} +1 -1
- package/dist/{manifest-schema-BXbUAHod.mjs → manifest-schema-BNWwR8Vd.mjs} +5 -5
- package/dist/manifest-schema-BNWwR8Vd.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +4 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +6 -4
- package/dist/media/image-endpoint.mjs.map +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +13 -3
- package/dist/media/index.mjs.map +1 -1
- package/dist/media/local-runtime.d.mts +14 -12
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +12 -6
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-CzhAn2--.mjs → media-BBm8Wg3f.mjs} +69 -12
- package/dist/media-BBm8Wg3f.mjs.map +1 -0
- package/dist/{media-BWWWb8kg.mjs → media-BHjus86Y.mjs} +133 -9
- package/dist/media-BHjus86Y.mjs.map +1 -0
- package/dist/{media-allowlist-D6x-Us02.mjs → media-allowlist-CoTBWoDp.mjs} +3 -2
- package/dist/media-allowlist-CoTBWoDp.mjs.map +1 -0
- package/dist/media-folders-BGkATs8n.mjs +210 -0
- package/dist/media-folders-BGkATs8n.mjs.map +1 -0
- package/dist/{media-upload-CHBVn6m-.mjs → media-upload-BCidR-EY.mjs} +9 -9
- package/dist/{media-upload-CHBVn6m-.mjs.map → media-upload-BCidR-EY.mjs.map} +1 -1
- package/dist/{media-url-BvoX88FA.mjs → media-url-DHoPr0hq.mjs} +1 -1
- package/dist/{media-url-BvoX88FA.mjs.map → media-url-DHoPr0hq.mjs.map} +1 -1
- package/dist/media-usage-CdY5jhSR.mjs +1833 -0
- package/dist/media-usage-CdY5jhSR.mjs.map +1 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs +78 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs.map +1 -0
- package/dist/{media-usage-work-CLo_6tct.mjs → media-usage-work-CnGCdHxx.mjs} +4 -4
- package/dist/{media-usage-work-CLo_6tct.mjs.map → media-usage-work-CnGCdHxx.mjs.map} +1 -1
- package/dist/{media-usage-work-DrCbqBcl.mjs → media-usage-work-D6D9sMCA.mjs} +221 -59
- package/dist/media-usage-work-D6D9sMCA.mjs.map +1 -0
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs → media-usage-write-fence-hjeD4u7s.mjs} +2 -2
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs.map → media-usage-write-fence-hjeD4u7s.mjs.map} +1 -1
- package/dist/{menus-DSo5QeW0.mjs → menus-6qSwTNxG.mjs} +375 -107
- package/dist/menus-6qSwTNxG.mjs.map +1 -0
- package/dist/{menus-TCNSd2vp.mjs → menus-uvPLXMZf.mjs} +4 -4
- package/dist/{menus-TCNSd2vp.mjs.map → menus-uvPLXMZf.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/{mime-DfIVjNkr.mjs → mime-CUIG6x84.mjs} +1 -1
- package/dist/mime-CUIG6x84.mjs.map +1 -0
- package/dist/{mode-BDoH_WcF.mjs → mode-DN_WneRx.mjs} +1 -1
- package/dist/{mode-BDoH_WcF.mjs.map → mode-DN_WneRx.mjs.map} +1 -1
- package/dist/node-sqlite-compat-BuJXIeMz.mjs +46 -0
- package/dist/node-sqlite-compat-BuJXIeMz.mjs.map +1 -0
- package/dist/{normalize-Bc-s_r-a.mjs → normalize-C2xNjTSG.mjs} +36 -5
- package/dist/normalize-C2xNjTSG.mjs.map +1 -0
- package/dist/{oauth-authorization-iOikmrJd.mjs → oauth-authorization-Dj6Kwc21.mjs} +5 -5
- package/dist/{oauth-authorization-iOikmrJd.mjs.map → oauth-authorization-Dj6Kwc21.mjs.map} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs → oauth-clients-FD7I0J8m.mjs} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs.map → oauth-clients-FD7I0J8m.mjs.map} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs → oauth-state-store-DkmDOmHs.mjs} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs.map → oauth-state-store-DkmDOmHs.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs → oauth-user-lookup-CvIwGpYd.mjs} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs.map → oauth-user-lookup-CvIwGpYd.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-71tPfV4A.mjs → object-cache-DVKnyOfy.mjs} +19 -3
- package/dist/object-cache-DVKnyOfy.mjs.map +1 -0
- package/dist/{options-CBXIHUoT.mjs → options-BHPeIbBd.mjs} +1 -1
- package/dist/{options-CBXIHUoT.mjs.map → options-BHPeIbBd.mjs.map} +1 -1
- package/dist/{options--hhz-jZ1.d.mts → options-CYb4y7hM.d.mts} +24 -11
- package/dist/options-CYb4y7hM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-DFbuc-Fh.mjs → parse-Ckpg-Qfp.mjs} +2 -2
- package/dist/{parse-DFbuc-Fh.mjs.map → parse-Ckpg-Qfp.mjs.map} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs → passkey-config-O_lj3y0k.mjs} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs.map → passkey-config-O_lj3y0k.mjs.map} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs → patterns-D9iDO3j8.mjs} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs.map → patterns-D9iDO3j8.mjs.map} +1 -1
- package/dist/{placeholder-Dp0K3RkD.d.mts → placeholder-4X9BrRrp.d.mts} +7 -1
- package/dist/placeholder-4X9BrRrp.d.mts.map +1 -0
- package/dist/plugin-types.d.mts +8 -3
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{policy-TluUIxuu.mjs → policy-Dhtwntrt.mjs} +2 -2
- package/dist/{policy-TluUIxuu.mjs.map → policy-Dhtwntrt.mjs.map} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs → portable-text-U85hOafW.mjs} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs.map → portable-text-U85hOafW.mjs.map} +1 -1
- package/dist/{preview-PW-nOnq4.mjs → preview-B_vJLvf8.mjs} +2 -2
- package/dist/{preview-PW-nOnq4.mjs.map → preview-B_vJLvf8.mjs.map} +1 -1
- package/dist/{protocol-DjsJHTlK.d.mts → protocol-JdD2YhY9.d.mts} +2 -2
- package/dist/{protocol-DjsJHTlK.d.mts.map → protocol-JdD2YhY9.d.mts.map} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs → public-url-CarhZJgf.mjs} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs.map → public-url-CarhZJgf.mjs.map} +1 -1
- package/dist/{query-zTVAR1Sl.mjs → query-BZKZcG5b.mjs} +15 -15
- package/dist/{query-zTVAR1Sl.mjs.map → query-BZKZcG5b.mjs.map} +1 -1
- package/dist/{query-BWs7O5Il.mjs → query-BndaFxxp.mjs} +5 -5
- package/dist/{query-BWs7O5Il.mjs.map → query-BndaFxxp.mjs.map} +1 -1
- package/dist/{rate-limit-Bx4g9m3p.mjs → rate-limit-BZmATC6W.mjs} +2 -2
- package/dist/{rate-limit-Bx4g9m3p.mjs.map → rate-limit-BZmATC6W.mjs.map} +1 -1
- package/dist/{redirect-COsS6SWJ.mjs → redirect-CZkbozu9.mjs} +2 -2
- package/dist/{redirect-COsS6SWJ.mjs.map → redirect-CZkbozu9.mjs.map} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs → redirect-CzqnLxK-.mjs} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs.map → redirect-CzqnLxK-.mjs.map} +1 -1
- package/dist/{redirects-DTDHWH31.mjs → redirects-BLNOWQTn.mjs} +64 -29
- package/dist/redirects-BLNOWQTn.mjs.map +1 -0
- package/dist/{redirects-DyChwDkG.mjs → redirects-CqzNM0KM.mjs} +5 -5
- package/dist/{redirects-DyChwDkG.mjs.map → redirects-CqzNM0KM.mjs.map} +1 -1
- package/dist/{registry-Cqa2I749.mjs → registry-AZAsRsor.mjs} +30 -126
- package/dist/registry-AZAsRsor.mjs.map +1 -0
- package/dist/{relation-BnHB0T4J.mjs → relation-04DfKRTO.mjs} +2 -2
- package/dist/{relation-BnHB0T4J.mjs.map → relation-04DfKRTO.mjs.map} +1 -1
- package/dist/{relations-BBApI4e2.mjs → relations-C4htk5sb.mjs} +7 -7
- package/dist/relations-C4htk5sb.mjs.map +1 -0
- package/dist/{relations-D5sM5fW0.mjs → relations-CcFwDJdJ.mjs} +4 -4
- package/dist/{relations-D5sM5fW0.mjs.map → relations-CcFwDJdJ.mjs.map} +1 -1
- package/dist/{relations-BHo5A8Zf.d.mts → relations-DnRK4YIT.d.mts} +347 -54
- package/dist/relations-DnRK4YIT.d.mts.map +1 -0
- package/dist/{request-cache-BSUptuJR.mjs → request-cache-DH9zdCOD.mjs} +1 -1
- package/dist/{request-cache-BSUptuJR.mjs.map → request-cache-DH9zdCOD.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DgZJh3zG.mjs → request-meta-DYxLlnmz.mjs} +2 -2
- package/dist/{request-meta-DgZJh3zG.mjs.map → request-meta-DYxLlnmz.mjs.map} +1 -1
- package/dist/{resolve-DOhVEvty.mjs → resolve-prZ3mP7l.mjs} +1 -1
- package/dist/{resolve-DOhVEvty.mjs.map → resolve-prZ3mP7l.mjs.map} +1 -1
- package/dist/{runner-C1T11CfC.mjs → runner-BLIDKpmA.mjs} +471 -290
- package/dist/runner-BLIDKpmA.mjs.map +1 -0
- package/dist/{runner-BYHZn3Jy.d.mts → runner-YKfIMnaF.d.mts} +3 -2
- package/dist/runner-YKfIMnaF.d.mts.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-DZ5YVVZj.mjs → schema-CGnBeLiW.mjs} +3 -3
- package/dist/{schema-DZ5YVVZj.mjs.map → schema-CGnBeLiW.mjs.map} +1 -1
- package/dist/{schema-2AOsSn2v.mjs → schema-DYr-Vd-L.mjs} +36 -6
- package/dist/{schema-2AOsSn2v.mjs.map → schema-DYr-Vd-L.mjs.map} +1 -1
- package/dist/{scopes-8ClPF2bC.mjs → scopes-BhWvBavj.mjs} +3 -3
- package/dist/{scopes-8ClPF2bC.mjs.map → scopes-BhWvBavj.mjs.map} +1 -1
- package/dist/{search-u1QYdOCG.mjs → search-C-qDk4kx.mjs} +4 -4
- package/dist/{search-u1QYdOCG.mjs.map → search-C-qDk4kx.mjs.map} +1 -1
- package/dist/{secrets-BEgsAQEU.mjs → secrets-rEtHt-6z.mjs} +3 -3
- package/dist/{secrets-BEgsAQEU.mjs.map → secrets-rEtHt-6z.mjs.map} +1 -1
- package/dist/{sections-DmHviGyM.mjs → sections-B_nYvlwn.mjs} +2 -2
- package/dist/{sections-DmHviGyM.mjs.map → sections-B_nYvlwn.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +25 -23
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +17 -15
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-Dq4G-RrO.mjs → seo-926NRIgt.mjs} +3 -3
- package/dist/{seo-Dq4G-RrO.mjs.map → seo-926NRIgt.mjs.map} +1 -1
- package/dist/{seo-AFpVvTqr.mjs → seo-CVWkdv6x.mjs} +1 -1
- package/dist/{seo-AFpVvTqr.mjs.map → seo-CVWkdv6x.mjs.map} +1 -1
- package/dist/{service-BpArayPr.mjs → service-CJl3ZAYs.mjs} +3 -3
- package/dist/{service-BpArayPr.mjs.map → service-CJl3ZAYs.mjs.map} +1 -1
- package/dist/{session-user-BEorKVT-.mjs → session-user-BlMgqCHS.mjs} +1 -1
- package/dist/{session-user-BEorKVT-.mjs.map → session-user-BlMgqCHS.mjs.map} +1 -1
- package/dist/{settings-xRdoUZr0.mjs → settings--wobrkkC.mjs} +21 -8
- package/dist/settings--wobrkkC.mjs.map +1 -0
- package/dist/{settings-DE9xtzqd.mjs → settings-Cwm6o2jY.mjs} +3 -3
- package/dist/{settings-DE9xtzqd.mjs.map → settings-Cwm6o2jY.mjs.map} +1 -1
- package/dist/{setup-complete-BnT8pq_C.mjs → setup-complete-DQbClIN2.mjs} +2 -2
- package/dist/{setup-complete-BnT8pq_C.mjs.map → setup-complete-DQbClIN2.mjs.map} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs → setup-nonce-DZCFS2sn.mjs} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs.map → setup-nonce-DZCFS2sn.mjs.map} +1 -1
- package/dist/{single-flight-cache-B0eLKS6K.mjs → single-flight-cache-BPuGPdcN.mjs} +2 -2
- package/dist/{single-flight-cache-B0eLKS6K.mjs.map → single-flight-cache-BPuGPdcN.mjs.map} +1 -1
- package/dist/{site-url-DjpIXMXJ.mjs → site-url-BrxA_E9H.mjs} +3 -3
- package/dist/{site-url-DjpIXMXJ.mjs.map → site-url-BrxA_E9H.mjs.map} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs → snapshot--OCDTqdb.mjs} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs.map → snapshot--OCDTqdb.mjs.map} +1 -1
- package/dist/{ssrf-Cpvg_n3A.mjs → ssrf-5sIM5jzl.mjs} +23 -6
- package/dist/{ssrf-Cpvg_n3A.mjs.map → ssrf-5sIM5jzl.mjs.map} +1 -1
- package/dist/{state-DYwPue40.mjs → state-BpFVsJZB.mjs} +12 -4
- package/dist/state-BpFVsJZB.mjs.map +1 -0
- package/dist/{status-CWVYpbD8.mjs → status-B777-dXz.mjs} +1 -1
- package/dist/{status-CWVYpbD8.mjs.map → status-B777-dXz.mjs.map} +1 -1
- package/dist/storage/local.d.mts +2 -1
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +2 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +3 -2
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{target-DixqqV5i.mjs → target-BmR0iTwz.mjs} +1 -1
- package/dist/{target-DixqqV5i.mjs.map → target-BmR0iTwz.mjs.map} +1 -1
- package/dist/{taxonomies-OHUIiIpI.mjs → taxonomies-DkAkMupr.mjs} +17 -14
- package/dist/taxonomies-DkAkMupr.mjs.map +1 -0
- package/dist/{taxonomies-BlrncHi9.mjs → taxonomies-Wfy_Lg12.mjs} +43 -17
- package/dist/taxonomies-Wfy_Lg12.mjs.map +1 -0
- package/dist/{taxonomy-BqCZ1TdU.mjs → taxonomy-tJepplLL.mjs} +5 -5
- package/dist/{taxonomy-BqCZ1TdU.mjs.map → taxonomy-tJepplLL.mjs.map} +1 -1
- package/dist/{tokens-C39klX8R.mjs → tokens-BCO1oruF.mjs} +1 -1
- package/dist/{tokens-C39klX8R.mjs.map → tokens-BCO1oruF.mjs.map} +1 -1
- package/dist/{transaction-NQj4VJ7Z.mjs → transaction-0KOpOyMu.mjs} +2 -1
- package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-0KOpOyMu.mjs.map} +1 -1
- package/dist/{transport-DBJwa-Si.mjs → transport-Dr3qtwXC.mjs} +4 -3
- package/dist/{transport-DBJwa-Si.mjs.map → transport-Dr3qtwXC.mjs.map} +1 -1
- package/dist/{transport-RQE36APG.d.mts → transport-xh6YKW2G.d.mts} +1 -1
- package/dist/{transport-RQE36APG.d.mts.map → transport-xh6YKW2G.d.mts.map} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs → trusted-proxy-BR5F1Otp.mjs} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs.map → trusted-proxy-BR5F1Otp.mjs.map} +1 -1
- package/dist/{types-BW1syrlw.mjs → types-3qNFPlci.mjs} +1 -1
- package/dist/{types-BW1syrlw.mjs.map → types-3qNFPlci.mjs.map} +1 -1
- package/dist/types-75KIqzL9.mjs.map +1 -1
- package/dist/{types-DrJrVCT1.d.mts → types-B6GrPic4.d.mts} +9 -3
- package/dist/{types-DrJrVCT1.d.mts.map → types-B6GrPic4.d.mts.map} +1 -1
- package/dist/{types-DN64_zzZ.d.mts → types-BuHW4xDE.d.mts} +11 -10
- package/dist/types-BuHW4xDE.d.mts.map +1 -0
- package/dist/{types-DWRhk9xZ.d.mts → types-C00oyCZp.d.mts} +1 -1
- package/dist/{types-DWRhk9xZ.d.mts.map → types-C00oyCZp.d.mts.map} +1 -1
- package/dist/{types-BntycPTF.d.mts → types-CDtkNSFQ.d.mts} +1 -1
- package/dist/{types-BntycPTF.d.mts.map → types-CDtkNSFQ.d.mts.map} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts → types-CPeXo1wF.d.mts} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts.map → types-CPeXo1wF.d.mts.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-BcqdcT-r.d.mts → types-CXFkwEGC.d.mts} +3 -2
- package/dist/types-CXFkwEGC.d.mts.map +1 -0
- package/dist/{types-CtzytVXn.mjs → types-DM3vioBY.mjs} +1 -1
- package/dist/{types-CtzytVXn.mjs.map → types-DM3vioBY.mjs.map} +1 -1
- package/dist/{types-CXnOzDe1.d.mts → types-DczELMop.d.mts} +1 -1
- package/dist/{types-CXnOzDe1.d.mts.map → types-DczELMop.d.mts.map} +1 -1
- package/dist/types-DfuTR6dL.mjs +3 -0
- package/dist/{types-DQIDRKF2.d.mts → types-FV23hEoW.d.mts} +10 -1
- package/dist/types-FV23hEoW.d.mts.map +1 -0
- package/dist/{types-C2pMvO62.d.mts → types-xDMtUFnO.d.mts} +2 -1
- package/dist/types-xDMtUFnO.d.mts.map +1 -0
- package/dist/{upload-attempts-D4FS8LT6.mjs → upload-attempts-BsqoQ1fn.mjs} +1 -1
- package/dist/{upload-attempts-D4FS8LT6.mjs.map → upload-attempts-BsqoQ1fn.mjs.map} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs → url-pattern-D4c2czpJ.mjs} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs.map → url-pattern-D4c2czpJ.mjs.map} +1 -1
- package/dist/{user-DJZfUJVE.mjs → user-BTZ40aq6.mjs} +2 -2
- package/dist/{user-DJZfUJVE.mjs.map → user-BTZ40aq6.mjs.map} +1 -1
- package/dist/{utils-D4vD_Y98.mjs → utils-BKvNjjhY.mjs} +1 -1
- package/dist/{utils-D4vD_Y98.mjs.map → utils-BKvNjjhY.mjs.map} +1 -1
- package/dist/{validate-BMLBvxOC.mjs → validate-DE_LRwo9.mjs} +2 -2
- package/dist/{validate-BMLBvxOC.mjs.map → validate-DE_LRwo9.mjs.map} +1 -1
- package/dist/{validate-CTqt5nuE.d.mts → validate-DUP27OYD.d.mts} +5 -5
- package/dist/{validate-CTqt5nuE.d.mts.map → validate-DUP27OYD.d.mts.map} +1 -1
- package/dist/{validation-npvENUCB.mjs → validation-BMImFJ11.mjs} +10 -8
- package/dist/{validation-npvENUCB.mjs.map → validation-BMImFJ11.mjs.map} +1 -1
- package/dist/version-Bii3suaO.mjs +7 -0
- package/dist/{version-DB_fqCSI.mjs.map → version-Bii3suaO.mjs.map} +1 -1
- package/dist/{widgets-BD3ho7Rq.mjs → widgets-D3gJ10xU.mjs} +18 -5
- package/dist/widgets-D3gJ10xU.mjs.map +1 -0
- package/dist/{wxr-taxonomies-Ca68766D.d.mts → wxr-taxonomies-B2Og_6rU.d.mts} +1 -1
- package/dist/{wxr-taxonomies-Ca68766D.d.mts.map → wxr-taxonomies-B2Og_6rU.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs → wxr-taxonomies-Cxngsjwo.mjs} +4 -4
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs.map → wxr-taxonomies-Cxngsjwo.mjs.map} +1 -1
- package/dist/{zod-generator-LC-on_Vb.mjs → zod-generator-BuYSQJB7.mjs} +32 -22
- package/dist/zod-generator-BuYSQJB7.mjs.map +1 -0
- package/package.json +20 -9
- package/src/api/errors.ts +22 -0
- package/src/api/handlers/content.ts +49 -11
- package/src/api/handlers/index.ts +18 -0
- package/src/api/handlers/manifest.ts +161 -12
- package/src/api/handlers/media-allowlist.ts +1 -0
- package/src/api/handlers/media-folders.ts +130 -0
- package/src/api/handlers/media-usage-activation.ts +102 -0
- package/src/api/handlers/media-usage.ts +108 -0
- package/src/api/handlers/media.ts +92 -2
- package/src/api/handlers/registry.ts +483 -561
- package/src/api/handlers/taxonomies.ts +16 -9
- package/src/api/openapi/document.ts +277 -7
- package/src/api/parse.ts +1 -1
- package/src/api/schemas/auth.ts +4 -4
- package/src/api/schemas/bylines.ts +3 -3
- package/src/api/schemas/comments.ts +1 -1
- package/src/api/schemas/common.ts +3 -2
- package/src/api/schemas/content.ts +78 -22
- package/src/api/schemas/media-usage.ts +77 -0
- package/src/api/schemas/media.ts +121 -0
- package/src/api/schemas/redirects.ts +6 -1
- package/src/api/schemas/schema.ts +4 -0
- package/src/api/schemas/setup.ts +1 -1
- package/src/api/schemas/taxonomies.ts +2 -2
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +23 -10
- package/src/astro/dev-typegen.ts +35 -0
- package/src/astro/image-endpoint.ts +2 -2
- package/src/astro/integration/dev-typegen.ts +91 -0
- package/src/astro/integration/index.ts +9 -44
- package/src/astro/integration/routes.ts +23 -0
- package/src/astro/integration/vite-config.ts +23 -9
- package/src/astro/middleware/auth.ts +4 -0
- package/src/astro/middleware.ts +5 -7
- package/src/astro/routes/api/admin/api-tokens/index.ts +4 -1
- package/src/astro/routes/api/admin/media-usage/activation.ts +42 -0
- package/src/astro/routes/api/admin/media-usage/progress.ts +37 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +1 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +1 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +247 -101
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +60 -0
- package/src/astro/routes/api/auth/me.ts +14 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +8 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +6 -2
- package/src/astro/routes/api/manifest.ts +1 -1
- package/src/astro/routes/api/media/[id]/replace.ts +114 -0
- package/src/astro/routes/api/media/[id].ts +3 -0
- package/src/astro/routes/api/media/file/[...key].ts +4 -1
- package/src/astro/routes/api/media/folders/[id].ts +55 -0
- package/src/astro/routes/api/media/folders/index.ts +37 -0
- package/src/astro/routes/api/media/upload-url.ts +8 -4
- package/src/astro/routes/api/media.ts +66 -10
- package/src/astro/routes/api/menus/[name]/items/[id].ts +7 -2
- package/src/astro/routes/api/menus/[name]/items.ts +4 -1
- package/src/astro/routes/api/menus/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/menus/[name]/translations.ts +4 -1
- package/src/astro/routes/api/menus/[name].ts +7 -2
- package/src/astro/routes/api/menus/index.ts +4 -1
- package/src/astro/routes/api/settings/email.ts +1 -1
- package/src/astro/routes/api/settings.ts +4 -1
- package/src/astro/routes/api/setup/dev-bypass.ts +12 -0
- package/src/astro/routes/api/taxonomies/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +7 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name].ts +7 -2
- package/src/astro/routes/api/taxonomies/index.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +5 -2
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name].ts +3 -1
- package/src/astro/routes/api/widget-areas/index.ts +3 -1
- package/src/astro/types.ts +34 -6
- package/src/auth/challenge-store.ts +3 -1
- package/src/aws-sdk.d.ts +1 -0
- package/src/cache/chrome-tags.ts +24 -0
- package/src/client/index.ts +140 -2
- package/src/client/transport.ts +6 -2
- package/src/components/EmDashImage.astro +156 -51
- package/src/components/EmDashMedia.astro +2 -1
- package/src/components/Gallery.astro +7 -0
- package/src/components/InlinePortableTextEditor.tsx +136 -2
- package/src/components/LiveSearch.astro +23 -0
- package/src/components/inline-code-block.tsx +180 -49
- package/src/components/widgets/Archives.astro +2 -37
- package/src/content/converters/gallery.ts +2 -0
- package/src/content/converters/index.ts +2 -0
- package/src/content/converters/mark-safety.ts +1 -0
- package/src/content/converters/portable-text-identity.ts +139 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +202 -69
- package/src/content/converters/prosemirror-to-portable-text.ts +96 -25
- package/src/content/converters/types.ts +3 -0
- package/src/database/connection.ts +2 -31
- package/src/database/index.ts +1 -1
- package/src/database/json-recordset.ts +16 -0
- package/src/database/migrations/017_authorization_codes.ts +14 -4
- package/src/database/migrations/019_i18n.ts +1 -1
- package/src/database/migrations/071_restore_content_bylines_table.ts +43 -0
- package/src/database/migrations/072_media_folders.ts +72 -0
- package/src/database/migrations/073_media_focal_point.ts +57 -0
- package/src/database/migrations/074_content_deleted_scheduled_index.ts +55 -0
- package/src/database/migrations/runner.ts +11 -3
- package/src/database/repositories/byline.ts +32 -16
- package/src/database/repositories/content.ts +119 -51
- package/src/database/repositories/media-folders.ts +115 -0
- package/src/database/repositories/media-usage-work.ts +395 -111
- package/src/database/repositories/media-usage.ts +1104 -47
- package/src/database/repositories/media.ts +156 -29
- package/src/database/repositories/plugin-storage.ts +74 -9
- package/src/database/repositories/types.ts +8 -7
- package/src/database/transaction.ts +1 -0
- package/src/database/types.ts +13 -0
- package/src/db/adapters.ts +10 -3
- package/src/db/node-sqlite-compat.ts +78 -0
- package/src/db/postgres.ts +23 -0
- package/src/db/sqlite.ts +3 -3
- package/src/emdash-runtime.ts +186 -251
- package/src/fields/boolean.ts +1 -1
- package/src/fields/datetime.ts +1 -1
- package/src/fields/file.ts +1 -1
- package/src/fields/image.ts +7 -1
- package/src/fields/integer.ts +1 -1
- package/src/fields/json.ts +1 -1
- package/src/fields/multiselect.ts +1 -1
- package/src/fields/number.ts +1 -1
- package/src/fields/portable-text.ts +1 -1
- package/src/fields/richtext.ts +1 -1
- package/src/fields/select.ts +1 -1
- package/src/fields/slug.ts +1 -1
- package/src/fields/text.ts +1 -1
- package/src/fields/textarea.ts +1 -1
- package/src/fields/types.ts +8 -4
- package/src/index.ts +30 -3
- package/src/loader.ts +63 -10
- package/src/mcp/server.ts +228 -24
- package/src/media/focal-point.ts +37 -0
- package/src/media/image-endpoint.ts +5 -2
- package/src/media/local-runtime.ts +8 -0
- package/src/media/mime.ts +1 -0
- package/src/media/normalize.ts +25 -4
- package/src/media/types.ts +10 -0
- package/src/media/usage/activation.ts +162 -35
- package/src/media/usage/capture-triggers.ts +19 -3
- package/src/media/usage/cleanup.ts +9 -8
- package/src/media/usage/collection-deletion-processor.ts +7 -3
- package/src/media/usage/collection-deletion.ts +10 -0
- package/src/media/usage/content-refresh.ts +258 -39
- package/src/media/usage/content-snapshots.ts +128 -31
- package/src/media/usage/extractor.ts +32 -13
- package/src/media/usage/maintenance-engine.ts +166 -0
- package/src/media/usage/reconciliation-processor.ts +106 -29
- package/src/media/usage/reconciliation.ts +90 -7
- package/src/media/usage/work-processor.ts +342 -101
- package/src/menus/index.ts +16 -0
- package/src/object-cache/index.ts +44 -2
- package/src/plugin-types.ts +18 -1
- package/src/plugins/hooks.ts +4 -1
- package/src/plugins/index.ts +7 -0
- package/src/plugins/manager.ts +2 -1
- package/src/plugins/manifest-schema.ts +1 -1
- package/src/plugins/routes.ts +3 -1
- package/src/plugins/sandbox/hook-result.ts +52 -0
- package/src/plugins/sandbox/index.ts +10 -0
- package/src/plugins/save-rejection.ts +20 -0
- package/src/plugins/scheduler/node.ts +1 -13
- package/src/plugins/scheduler/types.ts +0 -2
- package/src/plugins/state.ts +13 -3
- package/src/plugins/types.ts +6 -0
- package/src/registry/artifact-checksum.ts +15 -0
- package/src/registry/artifact-fetch.ts +530 -0
- package/src/registry/artifact-verification.ts +85 -0
- package/src/registry/authoritative-records.ts +180 -0
- package/src/registry/config.ts +24 -6
- package/src/registry/record-labels.ts +28 -0
- package/src/registry/types.ts +12 -15
- package/src/schema/registry.ts +26 -3
- package/src/schema/types.ts +1 -0
- package/src/schema/zod-generator.ts +28 -17
- package/src/security/ssrf.ts +26 -4
- package/src/seed/apply.ts +4 -4
- package/src/settings/index.ts +16 -0
- package/src/storage/local.ts +1 -0
- package/src/storage/s3.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/taxonomies/index.ts +40 -20
- package/src/ui.ts +2 -0
- package/src/widgets/archives.ts +67 -0
- package/src/widgets/index.ts +16 -0
- package/dist/api-BeBglVxU.mjs +0 -4695
- package/dist/api-BeBglVxU.mjs.map +0 -1
- package/dist/byline-yjvWq4ip.mjs.map +0 -1
- package/dist/challenge-store-SIL5DsF2.mjs.map +0 -1
- package/dist/collection-deletion-DQPvMD8R.mjs.map +0 -1
- package/dist/content-ZHCc1ngN.mjs.map +0 -1
- package/dist/content-refresh-B_8SJzuU.mjs.map +0 -1
- package/dist/context-ZldbZcle.mjs.map +0 -1
- package/dist/errors-CLUPm7aD.mjs.map +0 -1
- package/dist/index-BVBZj4-7.d.mts.map +0 -1
- package/dist/loader-CdG_Ci3H.mjs.map +0 -1
- package/dist/manifest-schema-BXbUAHod.mjs.map +0 -1
- package/dist/media-BWWWb8kg.mjs.map +0 -1
- package/dist/media-CzhAn2--.mjs.map +0 -1
- package/dist/media-allowlist-D6x-Us02.mjs.map +0 -1
- package/dist/media-usage-BZCydfvu.mjs.map +0 -1
- package/dist/media-usage-work-DrCbqBcl.mjs.map +0 -1
- package/dist/menus-DSo5QeW0.mjs.map +0 -1
- package/dist/mime-DfIVjNkr.mjs.map +0 -1
- package/dist/normalize-Bc-s_r-a.mjs.map +0 -1
- package/dist/object-cache-71tPfV4A.mjs.map +0 -1
- package/dist/options--hhz-jZ1.d.mts.map +0 -1
- package/dist/placeholder-Dp0K3RkD.d.mts.map +0 -1
- package/dist/redirects-DTDHWH31.mjs.map +0 -1
- package/dist/registry-Cqa2I749.mjs.map +0 -1
- package/dist/relations-BBApI4e2.mjs.map +0 -1
- package/dist/relations-BHo5A8Zf.d.mts.map +0 -1
- package/dist/runner-BYHZn3Jy.d.mts.map +0 -1
- package/dist/runner-C1T11CfC.mjs.map +0 -1
- package/dist/settings-xRdoUZr0.mjs.map +0 -1
- package/dist/state-DYwPue40.mjs.map +0 -1
- package/dist/taxonomies-BlrncHi9.mjs.map +0 -1
- package/dist/taxonomies-OHUIiIpI.mjs.map +0 -1
- package/dist/types-BcqdcT-r.d.mts.map +0 -1
- package/dist/types-C2pMvO62.d.mts.map +0 -1
- package/dist/types-CP1CflWf.mjs +0 -3
- package/dist/types-DN64_zzZ.d.mts.map +0 -1
- package/dist/types-DQIDRKF2.d.mts.map +0 -1
- package/dist/version-DB_fqCSI.mjs +0 -7
- package/dist/widgets-BD3ho7Rq.mjs.map +0 -1
- package/dist/zod-generator-LC-on_Vb.mjs.map +0 -1
- /package/dist/{api-tokens-rIXC6LdE.mjs → api-tokens-BfYts-sq.mjs} +0 -0
- /package/dist/{ssrf-DpXgKsna.mjs → ssrf-Dg3cIT-b.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-BLIDKpmA.mjs","names":["up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","upPostgres","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","getDefaultLocale","up","hasColumn","assertSingleLocale","down","up","down","up","down","up","isSearchEnabled","getSearchableFields","rebuildIndex","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","DUPLICATE_COLUMN_RE","up","down","addColumnIfMissing","deepErrorMessage","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down","ACTIVATION_KEY","DUPLICATE_COLUMN_RE","up","sortableUtcTimestamp","down","deepErrorMessage","up","down","up","sortableUtcTimestamp","down","up","down","up","down","up","down","up","down","up","down","up","down","DUPLICATE_COLUMN_RE","up","down","deepErrorMessage","up","down","deepErrorMessage","m001","m002","m003","m004","m005","m006","m007","m008","m009","m011","m012","m013","m014","m015","m016","m017","m018","m019","m020","m021","m022","m023","m024","m025","m026","m027","m028","m029","m030","m031","m032","m033","m034","m035","m036","m037","m038","m039","m040","m041","m042","m043","m044","m045","m046","m047","m048","m049","m050","m051","m052","m053","m054","m055","m056","m057","m058","m059","m060","m061","m062","m063","m064","m065","m066","m067","m068","m069","m070","m071","m072","m073","m074"],"sources":["../src/database/migrations/001_initial.ts","../src/database/migrations/002_media_status.ts","../src/database/migrations/003_schema_registry.ts","../src/database/migrations/004_plugins.ts","../src/database/migrations/005_menus.ts","../src/database/migrations/006_taxonomy_defs.ts","../src/database/migrations/007_widgets.ts","../src/database/migrations/008_auth.ts","../src/database/migrations/009_user_disabled.ts","../src/database/migrations/011_sections.ts","../src/database/migrations/012_search.ts","../src/database/migrations/013_scheduled_publishing.ts","../src/database/migrations/014_draft_revisions.ts","../src/database/migrations/015_indexes.ts","../src/database/migrations/016_api_tokens.ts","../src/database/migrations/017_authorization_codes.ts","../src/database/migrations/018_seo.ts","../src/database/migrations/019_i18n.ts","../src/database/migrations/020_collection_url_pattern.ts","../src/database/migrations/021_remove_section_categories.ts","../src/database/migrations/022_marketplace_plugin_state.ts","../src/database/migrations/023_plugin_metadata.ts","../src/database/migrations/024_media_placeholders.ts","../src/database/migrations/025_oauth_clients.ts","../src/database/migrations/026_cron_tasks.ts","../src/database/migrations/027_comments.ts","../src/database/migrations/028_drop_author_url.ts","../src/database/migrations/029_redirects.ts","../src/database/migrations/030_widen_scheduled_index.ts","../src/database/migrations/031_bylines.ts","../src/database/migrations/032_rate_limits.ts","../src/database/migrations/033_optimize_content_indexes.ts","../src/database/migrations/034_published_at_index.ts","../src/database/migrations/035_bounded_404_log.ts","../src/database/migrations/036_i18n_menus_and_taxonomies.ts","../src/database/migrations/037_credential_algorithm.ts","../src/database/migrations/038_registry_plugin_state.ts","../src/database/migrations/039_fix_fts5_triggers.ts","../src/database/migrations/040_byline_i18n.ts","../src/database/migrations/041_content_locale_list_index.ts","../src/database/migrations/042_byline_fields.ts","../src/database/migrations/043_content_references.ts","../src/database/migrations/044_comment_reactions.ts","../src/database/migrations/045_taxonomy_parent_group.ts","../src/database/migrations/046_media_usage_index.ts","../src/database/migrations/047_restore_taxonomy_parent_index.ts","../src/database/migrations/048_restore_content_taxonomies_term_index.ts","../src/database/migrations/049_taxonomies_name_locale_index.ts","../src/database/migrations/050_media_usage_index_status.ts","../src/database/migrations/051_content_taxonomies_denorm.ts","../src/database/migrations/052_media_usage_read_index.ts","../src/database/migrations/053_plugin_mcp_tools.ts","../src/database/migrations/054_media_upload_attempts.ts","../src/database/migrations/055_content_translation_group_locale_index.ts","../src/database/migrations/056_taxonomy_term_sort_order.ts","../src/database/migrations/057_collection_hidden.ts","../src/database/migrations/058_collection_sort_order.ts","../src/database/migrations/059_revision_prune_queue.ts","../src/database/migrations/060_collection_admin_config.ts","../src/database/migrations/061_media_usage_cleanup.ts","../src/database/migrations/062_media_usage_cleanup_fence.ts","../src/database/migrations/063_media_usage_incremental_work.ts","../src/database/migrations/064_fts_plain_text.ts","../src/database/migrations/065_media_usage_collection_deletion.ts","../src/database/migrations/066_media_usage_reconciliation.ts","../src/database/migrations/067_indexed_content_fields.ts","../src/database/migrations/068_content_taxonomy_entry_groups.ts","../src/database/migrations/069_collection_title_date_fields.ts","../src/database/migrations/070_collection_routable.ts","../src/database/migrations/071_restore_content_bylines_table.ts","../src/database/migrations/072_media_folders.ts","../src/database/migrations/073_media_focal_point.ts","../src/database/migrations/074_content_deleted_scheduled_index.ts","../src/database/migrations/runner.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Initial schema migration\n *\n * Note: Content tables (ec_posts, ec_pages, etc.) are created dynamically\n * by the SchemaRegistry when collections are added via the admin UI.\n * This migration only creates system tables.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Revisions - stores snapshots of content entries\n\t// References entries in ec_* tables by collection + entry_id\n\tawait db.schema\n\t\t.createTable(\"revisions\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull()) // e.g., 'posts'\n\t\t.addColumn(\"entry_id\", \"text\", (col) => col.notNull()) // ID in the ec_* table\n\t\t.addColumn(\"data\", \"text\", (col) => col.notNull()) // JSON snapshot of all fields\n\t\t.addColumn(\"author_id\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_revisions_entry\")\n\t\t.ifNotExists()\n\t\t.on(\"revisions\")\n\t\t.columns([\"collection\", \"entry_id\"])\n\t\t.execute();\n\n\t// Taxonomies\n\tawait db.schema\n\t\t.createTable(\"taxonomies\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"parent_id\", \"text\")\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addUniqueConstraint(\"taxonomies_name_slug_unique\", [\"name\", \"slug\"])\n\t\t.addForeignKeyConstraint(\"taxonomies_parent_fk\", [\"parent_id\"], \"taxonomies\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"set null\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_name\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.column(\"name\")\n\t\t.execute();\n\n\t// Content-Taxonomy junction - references entries in ec_* tables\n\tawait db.schema\n\t\t.createTable(\"content_taxonomies\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull()) // e.g., 'posts'\n\t\t.addColumn(\"entry_id\", \"text\", (col) => col.notNull()) // ID in the ec_* table\n\t\t.addColumn(\"taxonomy_id\", \"text\", (col) => col.notNull())\n\t\t.addPrimaryKeyConstraint(\"content_taxonomies_pk\", [\"collection\", \"entry_id\", \"taxonomy_id\"])\n\t\t.addForeignKeyConstraint(\n\t\t\t\"content_taxonomies_taxonomy_fk\",\n\t\t\t[\"taxonomy_id\"],\n\t\t\t\"taxonomies\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\t// Media\n\tawait db.schema\n\t\t.createTable(\"media\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"filename\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"mime_type\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"size\", \"integer\")\n\t\t.addColumn(\"width\", \"integer\")\n\t\t.addColumn(\"height\", \"integer\")\n\t\t.addColumn(\"alt\", \"text\")\n\t\t.addColumn(\"caption\", \"text\")\n\t\t.addColumn(\"storage_key\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"content_hash\", \"text\") // xxHash64 for deduplication\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"author_id\", \"text\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_media_content_hash\")\n\t\t.ifNotExists()\n\t\t.on(\"media\")\n\t\t.column(\"content_hash\")\n\t\t.execute();\n\n\t// Users\n\tawait db.schema\n\t\t.createTable(\"users\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"email\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"password_hash\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"name\", \"text\")\n\t\t.addColumn(\"role\", \"text\", (col) => col.defaultTo(\"subscriber\"))\n\t\t.addColumn(\"avatar_id\", \"text\")\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_users_email\")\n\t\t.ifNotExists()\n\t\t.on(\"users\")\n\t\t.column(\"email\")\n\t\t.execute();\n\n\t// Options (key-value store)\n\tawait db.schema\n\t\t.createTable(\"options\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"name\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"value\", \"text\", (col) => col.notNull())\n\t\t.execute();\n\n\t// Audit logs (security events)\n\tawait db.schema\n\t\t.createTable(\"audit_logs\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"timestamp\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"actor_id\", \"text\")\n\t\t.addColumn(\"actor_ip\", \"text\")\n\t\t.addColumn(\"action\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"resource_type\", \"text\")\n\t\t.addColumn(\"resource_id\", \"text\")\n\t\t.addColumn(\"details\", \"text\")\n\t\t.addColumn(\"status\", \"text\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_audit_actor\")\n\t\t.ifNotExists()\n\t\t.on(\"audit_logs\")\n\t\t.column(\"actor_id\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_audit_action\")\n\t\t.ifNotExists()\n\t\t.on(\"audit_logs\")\n\t\t.column(\"action\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_audit_timestamp\")\n\t\t.ifNotExists()\n\t\t.on(\"audit_logs\")\n\t\t.column(\"timestamp\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"audit_logs\").execute();\n\tawait db.schema.dropTable(\"options\").execute();\n\tawait db.schema.dropTable(\"users\").execute();\n\tawait db.schema.dropTable(\"media\").execute();\n\tawait db.schema.dropTable(\"content_taxonomies\").execute();\n\tawait db.schema.dropTable(\"taxonomies\").execute();\n\tawait db.schema.dropTable(\"revisions\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Add status column to media table for tracking upload state.\n * Status values: 'pending' | 'ready' | 'failed'\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.alterTable(\"media\")\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"ready\"))\n\t\t.execute();\n\n\tawait db.schema.createIndex(\"idx_media_status\").on(\"media\").column(\"status\").execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_media_status\").execute();\n\n\t// Note: SQLite doesn't support DROP COLUMN directly\n\t// For a proper down migration in SQLite, you'd need to:\n\t// 1. Create a new table without the column\n\t// 2. Copy data over\n\t// 3. Drop old table\n\t// 4. Rename new table\n\t// For simplicity, we'll leave this as a no-op since down migrations are rarely used\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Schema Registry Tables\n *\n * Creates the schema registry tables that store collection and field definitions.\n * This enables dynamic schema management where D1 is the source of truth.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Collection definitions (like WordPress post types, but stored in DB)\n\tawait db.schema\n\t\t.createTable(\"_emdash_collections\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"label_singular\", \"text\")\n\t\t.addColumn(\"description\", \"text\")\n\t\t.addColumn(\"icon\", \"text\")\n\t\t.addColumn(\"supports\", \"text\") // JSON array: [\"revisions\", \"drafts\", \"preview\"]\n\t\t.addColumn(\"source\", \"text\") // 'template:blog', 'import:wordpress', 'manual'\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Field definitions for each collection\n\tawait db.schema\n\t\t.createTable(\"_emdash_fields\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"collection_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull()) // 'string', 'number', 'boolean', 'portableText', etc.\n\t\t.addColumn(\"column_type\", \"text\", (col) => col.notNull()) // 'TEXT', 'REAL', 'INTEGER', 'JSON'\n\t\t.addColumn(\"required\", \"integer\", (col) => col.defaultTo(0)) // boolean as 0/1\n\t\t.addColumn(\"unique\", \"integer\", (col) => col.defaultTo(0)) // boolean as 0/1\n\t\t.addColumn(\"default_value\", \"text\") // JSON-encoded default\n\t\t.addColumn(\"validation\", \"text\") // JSON: { min: 0, max: 100, pattern: \"^[a-z]+$\" }\n\t\t.addColumn(\"widget\", \"text\") // UI widget hint: 'textarea', 'richtext', 'select'\n\t\t.addColumn(\"options\", \"text\") // JSON: widget-specific config\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\n\t\t\t\"fields_collection_fk\",\n\t\t\t[\"collection_id\"],\n\t\t\t\"_emdash_collections\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\t// Unique constraint on collection + field slug\n\tawait db.schema\n\t\t.createIndex(\"idx_fields_collection_slug\")\n\t\t.on(\"_emdash_fields\")\n\t\t.columns([\"collection_id\", \"slug\"])\n\t\t.unique()\n\t\t.execute();\n\n\t// Index for faster field lookups\n\tawait db.schema\n\t\t.createIndex(\"idx_fields_collection\")\n\t\t.on(\"_emdash_fields\")\n\t\t.column(\"collection_id\")\n\t\t.execute();\n\n\t// Index for sorting\n\tawait db.schema\n\t\t.createIndex(\"idx_fields_sort\")\n\t\t.on(\"_emdash_fields\")\n\t\t.columns([\"collection_id\", \"sort_order\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_fields\").execute();\n\tawait db.schema.dropTable(\"_emdash_collections\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Plugin System Tables\n *\n * Creates the plugin storage table and plugin state tracking.\n * Plugin storage uses a document store with declared indexes.\n *\n * @see PLUGIN-SYSTEM.md § Plugin Storage\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Core storage table for plugin documents\n\tawait db.schema\n\t\t.createTable(\"_plugin_storage\")\n\t\t.addColumn(\"plugin_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"data\", \"text\", (col) => col.notNull()) // JSON\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"pk_plugin_storage\", [\"plugin_id\", \"collection\", \"id\"])\n\t\t.execute();\n\n\t// Base index for listing\n\tawait db.schema\n\t\t.createIndex(\"idx_plugin_storage_list\")\n\t\t.on(\"_plugin_storage\")\n\t\t.columns([\"plugin_id\", \"collection\", \"created_at\"])\n\t\t.execute();\n\n\t// Plugin state tracking for lifecycle hooks\n\tawait db.schema\n\t\t.createTable(\"_plugin_state\")\n\t\t.addColumn(\"plugin_id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"version\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"installed\")) // installed, active, inactive\n\t\t.addColumn(\"installed_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"activated_at\", \"text\")\n\t\t.addColumn(\"deactivated_at\", \"text\")\n\t\t.addColumn(\"data\", \"text\") // JSON for plugin-specific state\n\t\t.execute();\n\n\t// Index tracking for dynamic expression indexes on plugin storage\n\t// This tracks which indexes have been created so we can manage them\n\tawait db.schema\n\t\t.createTable(\"_plugin_indexes\")\n\t\t.addColumn(\"plugin_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"index_name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"fields\", \"text\", (col) => col.notNull()) // JSON array of field paths\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"pk_plugin_indexes\", [\"plugin_id\", \"collection\", \"index_name\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_plugin_indexes\").execute();\n\tawait db.schema.dropTable(\"_plugin_state\").execute();\n\tawait db.schema.dropTable(\"_plugin_storage\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Navigation Menus migration\n *\n * Creates tables for admin-editable navigation menus.\n * Menu items can reference content entries, taxonomy terms, or custom URLs.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Menu definitions\n\tawait db.schema\n\t\t.createTable(\"_emdash_menus\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Menu items (ordered, hierarchical)\n\tawait db.schema\n\t\t.createTable(\"_emdash_menu_items\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"menu_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"parent_id\", \"text\")\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull()) // 'page', 'post', 'custom', 'taxonomy', 'collection'\n\t\t.addColumn(\"reference_collection\", \"text\")\n\t\t.addColumn(\"reference_id\", \"text\")\n\t\t.addColumn(\"custom_url\", \"text\")\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"title_attr\", \"text\")\n\t\t.addColumn(\"target\", \"text\")\n\t\t.addColumn(\"css_classes\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"menu_items_menu_fk\", [\"menu_id\"], \"_emdash_menus\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.addForeignKeyConstraint(\n\t\t\t\"menu_items_parent_fk\",\n\t\t\t[\"parent_id\"],\n\t\t\t\"_emdash_menu_items\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\t// Index for efficient menu item queries\n\tawait db.schema\n\t\t.createIndex(\"idx_menu_items_menu\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.columns([\"menu_id\", \"sort_order\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_menu_items_parent\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_menu_items\").execute();\n\tawait db.schema.dropTable(\"_emdash_menus\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Taxonomy definitions migration\n *\n * Adds _emdash_taxonomy_defs table to store taxonomy definitions (category, tag, custom)\n * and seeds default category and tag taxonomies.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Taxonomy definitions (what taxonomies exist)\n\tawait db.schema\n\t\t.createTable(\"_emdash_taxonomy_defs\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull().unique()) // 'category', 'tag'\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull()) // 'Categories'\n\t\t.addColumn(\"label_singular\", \"text\") // 'Category'\n\t\t.addColumn(\"hierarchical\", \"integer\", (col) => col.defaultTo(0)) // 0 or 1\n\t\t.addColumn(\"collections\", \"text\") // JSON array: [\"posts\"]\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Seed default taxonomies\n\tawait db\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely migration runs against unknown schema\n\t\t.insertInto(\"_emdash_taxonomy_defs\" as never)\n\t\t.values([\n\t\t\t{\n\t\t\t\tid: \"taxdef_category\",\n\t\t\t\tname: \"category\",\n\t\t\t\tlabel: \"Categories\",\n\t\t\t\tlabel_singular: \"Category\",\n\t\t\t\thierarchical: 1,\n\t\t\t\tcollections: JSON.stringify([\"posts\"]),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"taxdef_tag\",\n\t\t\t\tname: \"tag\",\n\t\t\t\tlabel: \"Tags\",\n\t\t\t\tlabel_singular: \"Tag\",\n\t\t\t\thierarchical: 0,\n\t\t\t\tcollections: JSON.stringify([\"posts\"]),\n\t\t\t},\n\t\t])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_taxonomy_defs\").execute();\n}\n","import { type Kysely, sql } from \"kysely\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Widget areas table\n\tawait db.schema\n\t\t.createTable(\"_emdash_widget_areas\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"description\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.execute();\n\n\t// Widgets table\n\tawait db.schema\n\t\t.createTable(\"_emdash_widgets\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"area_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_widget_areas.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull()) // 'content', 'menu', 'component'\n\t\t.addColumn(\"title\", \"text\")\n\t\t.addColumn(\"content\", \"text\") // JSON: Portable Text for content type\n\t\t.addColumn(\"menu_name\", \"text\") // For menu type\n\t\t.addColumn(\"component_id\", \"text\") // For component type: 'core:recent-posts'\n\t\t.addColumn(\"component_props\", \"text\") // JSON: props for component\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.execute();\n\n\t// Index for efficient lookups by area and order\n\tawait db.schema\n\t\t.createIndex(\"idx_widgets_area\")\n\t\t.on(\"_emdash_widgets\")\n\t\t.columns([\"area_id\", \"sort_order\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_widgets\").execute();\n\tawait db.schema.dropTable(\"_emdash_widget_areas\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { binaryType, currentTimestamp, currentTimestampValue } from \"../dialect-helpers.js\";\n\n/**\n * Auth migration - passkey-first authentication\n *\n * Changes:\n * - Removes password_hash from users (no passwords)\n * - Adds role as integer (RBAC levels)\n * - Adds email_verified, avatar_url, updated_at to users\n * - Creates credentials table (passkeys)\n * - Creates auth_tokens table (magic links, invites)\n * - Creates oauth_accounts table (external provider links)\n * - Creates allowed_domains table (self-signup)\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// SQLite doesn't support DROP COLUMN directly, so we need to recreate the table\n\t// Create new users table with updated schema\n\tawait db.schema\n\t\t.createTable(\"users_new\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"email\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"name\", \"text\")\n\t\t.addColumn(\"avatar_url\", \"text\")\n\t\t.addColumn(\"role\", \"integer\", (col) => col.notNull().defaultTo(10)) // SUBSCRIBER\n\t\t.addColumn(\"email_verified\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Migrate existing data (map old role strings to new integer levels)\n\tawait sql`\n\t\tINSERT INTO users_new (id, email, name, role, data, created_at, updated_at)\n\t\tSELECT\n\t\t\tid,\n\t\t\temail,\n\t\t\tname,\n\t\t\tCASE role\n\t\t\t\tWHEN 'admin' THEN 50\n\t\t\t\tWHEN 'editor' THEN 40\n\t\t\t\tWHEN 'author' THEN 30\n\t\t\t\tWHEN 'contributor' THEN 20\n\t\t\t\tELSE 10\n\t\t\tEND,\n\t\t\tdata,\n\t\t\tcreated_at,\n\t\t\t${currentTimestampValue(db)}\n\t\tFROM users\n\t`.execute(db);\n\n\t// Drop old table and rename new one\n\tawait db.schema.dropTable(\"users\").execute();\n\tawait sql`ALTER TABLE users_new RENAME TO users`.execute(db);\n\n\t// Recreate index\n\tawait db.schema.createIndex(\"idx_users_email\").on(\"users\").column(\"email\").execute();\n\n\t// Passkey credentials\n\tawait db.schema\n\t\t.createTable(\"credentials\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey()) // Base64url credential ID\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"public_key\", binaryType(db), (col) => col.notNull()) // COSE public key\n\t\t.addColumn(\"counter\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"device_type\", \"text\", (col) => col.notNull()) // 'singleDevice' | 'multiDevice'\n\t\t.addColumn(\"backed_up\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"transports\", \"text\") // JSON array\n\t\t.addColumn(\"name\", \"text\") // User-friendly name\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"last_used_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"credentials_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema.createIndex(\"idx_credentials_user\").on(\"credentials\").column(\"user_id\").execute();\n\n\t// Auth tokens (magic links, email verification, invites, recovery)\n\tawait db.schema\n\t\t.createTable(\"auth_tokens\")\n\t\t.addColumn(\"hash\", \"text\", (col) => col.primaryKey()) // SHA-256 hash of token\n\t\t.addColumn(\"user_id\", \"text\")\n\t\t.addColumn(\"email\", \"text\") // For pre-user tokens\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull()) // 'magic_link' | 'email_verify' | 'invite' | 'recovery'\n\t\t.addColumn(\"role\", \"integer\") // For invites\n\t\t.addColumn(\"invited_by\", \"text\")\n\t\t.addColumn(\"expires_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"auth_tokens_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.addForeignKeyConstraint(\"auth_tokens_invited_by_fk\", [\"invited_by\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"set null\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema.createIndex(\"idx_auth_tokens_email\").on(\"auth_tokens\").column(\"email\").execute();\n\n\t// OAuth accounts (external provider links)\n\tawait db.schema\n\t\t.createTable(\"oauth_accounts\")\n\t\t.addColumn(\"provider\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"provider_account_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"oauth_accounts_pk\", [\"provider\", \"provider_account_id\"])\n\t\t.addForeignKeyConstraint(\"oauth_accounts_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_oauth_accounts_user\")\n\t\t.on(\"oauth_accounts\")\n\t\t.column(\"user_id\")\n\t\t.execute();\n\n\t// Allowed domains for self-signup\n\tawait db.schema\n\t\t.createTable(\"allowed_domains\")\n\t\t.addColumn(\"domain\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"default_role\", \"integer\", (col) => col.notNull().defaultTo(20)) // CONTRIBUTOR\n\t\t.addColumn(\"enabled\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// WebAuthn challenges (ephemeral, with TTL)\n\tawait db.schema\n\t\t.createTable(\"auth_challenges\")\n\t\t.addColumn(\"challenge\", \"text\", (col) => col.primaryKey()) // Base64url challenge\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull()) // 'registration' | 'authentication'\n\t\t.addColumn(\"user_id\", \"text\") // For registration, the user being registered\n\t\t.addColumn(\"data\", \"text\") // JSON for additional context\n\t\t.addColumn(\"expires_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Index for efficient cleanup of expired challenges\n\tawait db.schema\n\t\t.createIndex(\"idx_auth_challenges_expires\")\n\t\t.on(\"auth_challenges\")\n\t\t.column(\"expires_at\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// Drop new tables\n\tawait db.schema.dropTable(\"auth_challenges\").execute();\n\tawait db.schema.dropTable(\"allowed_domains\").execute();\n\tawait db.schema.dropTable(\"oauth_accounts\").execute();\n\tawait db.schema.dropTable(\"auth_tokens\").execute();\n\tawait db.schema.dropTable(\"credentials\").execute();\n\n\t// Recreate old users table with password_hash\n\tawait db.schema\n\t\t.createTable(\"users_old\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"email\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"password_hash\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"name\", \"text\")\n\t\t.addColumn(\"role\", \"text\", (col) => col.defaultTo(\"subscriber\"))\n\t\t.addColumn(\"avatar_id\", \"text\")\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Migrate data back (users will have empty password_hash)\n\tawait sql`\n\t\tINSERT INTO users_old (id, email, password_hash, name, role, data, created_at)\n\t\tSELECT\n\t\t\tid,\n\t\t\temail,\n\t\t\t'', -- No way to restore password\n\t\t\tname,\n\t\t\tCASE role\n\t\t\t\tWHEN 50 THEN 'admin'\n\t\t\t\tWHEN 40 THEN 'editor'\n\t\t\t\tWHEN 30 THEN 'author'\n\t\t\t\tWHEN 20 THEN 'contributor'\n\t\t\t\tELSE 'subscriber'\n\t\t\tEND,\n\t\t\tdata,\n\t\t\tcreated_at\n\t\tFROM users\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"users\").execute();\n\tawait sql`ALTER TABLE users_old RENAME TO users`.execute(db);\n\n\tawait db.schema.createIndex(\"idx_users_email\").on(\"users\").column(\"email\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * User disabled column - for soft-disabling users\n *\n * Changes:\n * - Adds disabled column to users table (INTEGER, default 0)\n * - Disabled users cannot log in\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// SQLite supports ADD COLUMN\n\tawait sql`ALTER TABLE users ADD COLUMN disabled INTEGER NOT NULL DEFAULT 0`.execute(db);\n\n\t// Create index for querying active users\n\tawait db.schema.createIndex(\"idx_users_disabled\").on(\"users\").column(\"disabled\").execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// SQLite doesn't support DROP COLUMN directly, but we can drop the index\n\t// For full rollback, table would need to be recreated\n\tawait db.schema.dropIndex(\"idx_users_disabled\").execute();\n\n\t// SQLite 3.35.0+ supports DROP COLUMN, but for compatibility:\n\t// We'll leave the column but document that it's deprecated\n\t// In production, you'd recreate the table without the column\n}\n","import { type Kysely, sql } from \"kysely\";\n\n/**\n * Migration: Add sections tables and performance indexes\n *\n * Sections are reusable content blocks that can be inserted into any Portable Text field.\n * They provide a library of pre-built page sections (heroes, CTAs, testimonials, etc.)\n * that content authors can browse and insert with a single click.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Section categories table\n\tawait db.schema\n\t\t.createTable(\"_emdash_section_categories\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.execute();\n\n\t// Sections table\n\tawait db.schema\n\t\t.createTable(\"_emdash_sections\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"title\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"description\", \"text\")\n\t\t// Categorization\n\t\t.addColumn(\"category_id\", \"text\", (col) =>\n\t\t\tcol.references(\"_emdash_section_categories.id\").onDelete(\"set null\"),\n\t\t)\n\t\t.addColumn(\"keywords\", \"text\") // JSON array for search\n\t\t// Content (Portable Text array)\n\t\t.addColumn(\"content\", \"text\", (col) => col.notNull()) // JSON\n\t\t// Preview image (optional)\n\t\t.addColumn(\"preview_media_id\", \"text\")\n\t\t// Source tracking\n\t\t.addColumn(\"source\", \"text\", (col) => col.notNull().defaultTo(\"user\")) // 'theme', 'user', 'import'\n\t\t.addColumn(\"theme_id\", \"text\") // Which theme provided it (if source='theme')\n\t\t// Metadata\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.execute();\n\n\t// Index for efficient category lookups\n\tawait db.schema\n\t\t.createIndex(\"idx_sections_category\")\n\t\t.on(\"_emdash_sections\")\n\t\t.columns([\"category_id\"])\n\t\t.execute();\n\n\t// Index for filtering by source\n\tawait db.schema\n\t\t.createIndex(\"idx_sections_source\")\n\t\t.on(\"_emdash_sections\")\n\t\t.columns([\"source\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_sections_source\").execute();\n\tawait db.schema.dropIndex(\"idx_sections_category\").execute();\n\tawait db.schema.dropTable(\"_emdash_sections\").execute();\n\tawait db.schema.dropTable(\"_emdash_section_categories\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Migration: Search Support\n *\n * Adds search configuration to collections and searchable flag to fields.\n * FTS5 tables are created dynamically when search is enabled for a collection.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Add search_config to collections (JSON: { enabled, weights })\n\tawait db.schema.alterTable(\"_emdash_collections\").addColumn(\"search_config\", \"text\").execute();\n\n\t// Add searchable flag to fields\n\tawait db.schema\n\t\t.alterTable(\"_emdash_fields\")\n\t\t.addColumn(\"searchable\", \"integer\", (col) => col.defaultTo(0))\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// SQLite doesn't support DROP COLUMN in older versions, but modern SQLite does\n\t// These columns are safe to drop\n\tawait db.schema.alterTable(\"_emdash_fields\").dropColumn(\"searchable\").execute();\n\tawait db.schema.alterTable(\"_emdash_collections\").dropColumn(\"search_config\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Add scheduled publishing support\n *\n * Adds scheduled_at column to all ec_* content tables.\n * When scheduled_at is set and status is 'scheduled', the content\n * will be auto-published when the scheduled time is reached.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Get all ec_* content tables\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\t// Add scheduled_at column to each content table\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(table.name)} \n\t\t\tADD COLUMN scheduled_at TEXT\n\t\t`.execute(db);\n\n\t\t// Create index for efficient scheduled content queries\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_scheduled`)} \n\t\t\tON ${sql.ref(table.name)} (scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL AND status = 'scheduled'\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// Get all ec_* content tables\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\t// Drop scheduled_at column from each content table\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\t\t// Drop index first\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_scheduled`)}\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(table.name)} \n\t\t\tDROP COLUMN scheduled_at\n\t\t`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Get all content tables\n\tconst tables = await db\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely migration runs against unknown schema\n\t\t.selectFrom(\"_emdash_collections\" as never)\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely migration runs against unknown schema\n\t\t.select(\"slug\" as never)\n\t\t.execute();\n\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely execute returns unknown[]; narrowing to known shape\n\tfor (const row of tables as Array<{ slug: string }>) {\n\t\tconst tableName = `ec_${row.slug}`;\n\n\t\t// Add live_revision_id column\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tADD COLUMN live_revision_id TEXT REFERENCES revisions(id)\n\t\t`.execute(db);\n\n\t\t// Add draft_revision_id column\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tADD COLUMN draft_revision_id TEXT REFERENCES revisions(id)\n\t\t`.execute(db);\n\n\t\t// Create indexes for the new columns\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${row.slug}_live_revision`)}\n\t\t\tON ${sql.ref(tableName)} (live_revision_id)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${row.slug}_draft_revision`)}\n\t\t\tON ${sql.ref(tableName)} (draft_revision_id)\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tables = await db\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely migration runs against unknown schema\n\t\t.selectFrom(\"_emdash_collections\" as never)\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely migration runs against unknown schema\n\t\t.select(\"slug\" as never)\n\t\t.execute();\n\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Kysely execute returns unknown[]; narrowing to known shape\n\tfor (const row of tables as Array<{ slug: string }>) {\n\t\tconst tableName = `ec_${row.slug}`;\n\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${row.slug}_draft_revision`)}\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${row.slug}_live_revision`)}\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tDROP COLUMN draft_revision_id\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tDROP COLUMN live_revision_id\n\t\t`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Add performance indexes for common query patterns.\n *\n * Covers:\n * 1. Media table: mime_type, filename, created_at\n * 2. content_taxonomies: reverse lookup by taxonomy_id\n * 3. taxonomies: parent_id FK\n * 4. audit_logs: compound (resource_type, resource_id)\n * 5. Retroactive author_id + updated_at on existing ec_* content tables\n * (new tables get these from createContentTable() in registry.ts)\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// ── Media indexes ────────────────────────────────────────────────\n\tawait db.schema.createIndex(\"idx_media_mime_type\").on(\"media\").column(\"mime_type\").execute();\n\tawait db.schema.createIndex(\"idx_media_filename\").on(\"media\").column(\"filename\").execute();\n\tawait db.schema.createIndex(\"idx_media_created_at\").on(\"media\").column(\"created_at\").execute();\n\n\t// ── Taxonomy indexes ─────────────────────────────────────────────\n\t// Reverse lookup: find entries with a specific term\n\tawait db.schema\n\t\t.createIndex(\"idx_content_taxonomies_term\")\n\t\t.on(\"content_taxonomies\")\n\t\t.column(\"taxonomy_id\")\n\t\t.execute();\n\n\t// Hierarchical queries filter on parent_id FK\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_parent\")\n\t\t.on(\"taxonomies\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n\n\t// ── Audit log indexes ────────────────────────────────────────────\n\t// findByResource() compound query\n\tawait db.schema\n\t\t.createIndex(\"idx_audit_resource\")\n\t\t.on(\"audit_logs\")\n\t\t.columns([\"resource_type\", \"resource_id\"])\n\t\t.execute();\n\n\t// ── Retroactive content table indexes ────────────────────────────\n\t// Add author_id and updated_at indexes to all existing ec_* tables.\n\t// New tables created after this migration get these from createContentTable().\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_author`)} \n\t\t\tON ${sql.ref(table.name)} (author_id)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_updated`)} \n\t\t\tON ${sql.ref(table.name)} (updated_at)\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// Drop retroactive content table indexes\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_updated`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_author`)}`.execute(db);\n\t}\n\n\t// Drop system table indexes\n\tawait db.schema.dropIndex(\"idx_audit_resource\").execute();\n\tawait db.schema.dropIndex(\"idx_taxonomies_parent\").execute();\n\tawait db.schema.dropIndex(\"idx_content_taxonomies_term\").execute();\n\tawait db.schema.dropIndex(\"idx_media_created_at\").execute();\n\tawait db.schema.dropIndex(\"idx_media_filename\").execute();\n\tawait db.schema.dropIndex(\"idx_media_mime_type\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * API token tables for programmatic access.\n *\n * Three tables:\n * 1. _emdash_api_tokens — Personal Access Tokens (ec_pat_...)\n * 2. _emdash_oauth_tokens — OAuth access/refresh tokens (ec_oat_/ec_ort_...)\n * 3. _emdash_device_codes — OAuth Device Flow state (RFC 8628)\n *\n * Every CREATE is guarded with `.ifNotExists()` so the migration is safe to\n * re-run against a partially-applied schema. See #954 for the failure mode:\n * if `up()` crashes mid-way (D1 subrequest limit, isolate cancellation,\n * transient connection error), the migration record never gets inserted\n * into `_emdash_migrations`, and the next request retries `up()` from the\n * top. Without these guards, the retry crashed with `table ... already\n * exists` and blocked every subsequent boot of the Worker.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// ── Personal Access Tokens ───────────────────────────────────────\n\tawait db.schema\n\t\t.createTable(\"_emdash_api_tokens\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"token_hash\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"prefix\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"scopes\", \"text\", (col) => col.notNull()) // JSON array\n\t\t.addColumn(\"expires_at\", \"text\") // null = no expiry\n\t\t.addColumn(\"last_used_at\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"api_tokens_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_api_tokens_token_hash\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_api_tokens\")\n\t\t.column(\"token_hash\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_api_tokens_user_id\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_api_tokens\")\n\t\t.column(\"user_id\")\n\t\t.execute();\n\n\t// ── OAuth Tokens ─────────────────────────────────────────────────\n\tawait db.schema\n\t\t.createTable(\"_emdash_oauth_tokens\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"token_hash\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"token_type\", \"text\", (col) => col.notNull()) // 'access' | 'refresh'\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"scopes\", \"text\", (col) => col.notNull()) // JSON array\n\t\t.addColumn(\"client_type\", \"text\", (col) => col.notNull().defaultTo(\"cli\"))\n\t\t.addColumn(\"expires_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"refresh_token_hash\", \"text\") // links access → refresh\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"oauth_tokens_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_oauth_tokens_user_id\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_oauth_tokens\")\n\t\t.column(\"user_id\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_oauth_tokens_expires\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_oauth_tokens\")\n\t\t.column(\"expires_at\")\n\t\t.execute();\n\n\t// ── Device Codes (OAuth Device Flow, RFC 8628) ───────────────────\n\tawait db.schema\n\t\t.createTable(\"_emdash_device_codes\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"device_code\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"user_code\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"scopes\", \"text\", (col) => col.notNull()) // JSON array\n\t\t.addColumn(\"user_id\", \"text\") // set when user authorizes\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"pending\"))\n\t\t.addColumn(\"expires_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"interval\", \"integer\", (col) => col.notNull().defaultTo(5))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_device_codes\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_oauth_tokens\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_api_tokens\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists, currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Authorization codes for OAuth 2.1 Authorization Code + PKCE flow.\n *\n * Used by MCP clients (Claude Desktop, VS Code, etc.) to authenticate\n * via the standard OAuth authorization code grant.\n *\n * Also adds client_id tracking to oauth_tokens for per-client revocation.\n *\n * Every statement is guarded so the migration can restart after any one of\n * them has committed. D1 commits each DDL statement on its own and the\n * migrator records the migration only once `up` returns, so an interrupted\n * run leaves the table created and the migration pending; an unguarded\n * `CREATE TABLE` then fails on every retry and the database never finishes\n * migrating.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_authorization_codes\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"code_hash\", \"text\", (col) => col.primaryKey()) // SHA-256 hash of authorization code\n\t\t.addColumn(\"client_id\", \"text\", (col) => col.notNull()) // CIMD URL or opaque string\n\t\t.addColumn(\"redirect_uri\", \"text\", (col) => col.notNull()) // Must match exactly on exchange\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"scopes\", \"text\", (col) => col.notNull()) // JSON array\n\t\t.addColumn(\"code_challenge\", \"text\", (col) => col.notNull()) // S256 challenge\n\t\t.addColumn(\"code_challenge_method\", \"text\", (col) => col.notNull().defaultTo(\"S256\"))\n\t\t.addColumn(\"resource\", \"text\") // RFC 8707 resource indicator\n\t\t.addColumn(\"expires_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addForeignKeyConstraint(\"auth_codes_user_fk\", [\"user_id\"], \"users\", [\"id\"], (cb) =>\n\t\t\tcb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_auth_codes_expires\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_authorization_codes\")\n\t\t.column(\"expires_at\")\n\t\t.execute();\n\n\t// Track which client obtained a token (for per-client revocation)\n\tif (!(await columnExists(db, \"_emdash_oauth_tokens\", \"client_id\"))) {\n\t\tawait db.schema.alterTable(\"_emdash_oauth_tokens\").addColumn(\"client_id\", \"text\").execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_authorization_codes\").ifExists().execute();\n\t// SQLite doesn't support DROP COLUMN, but this is only for dev rollback\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Migration: SEO support\n *\n * Creates:\n * - `_emdash_seo` table: per-content SEO metadata (separate from content tables)\n * - `has_seo` column on `_emdash_collections`: opt-in flag per collection\n *\n * SEO is not a universal concern — only collections representing web pages\n * need it. The `has_seo` flag controls whether the admin shows SEO fields\n * and whether the collection's content appears in sitemaps.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Create the SEO table\n\tawait db.schema\n\t\t.createTable(\"_emdash_seo\")\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"seo_title\", \"text\")\n\t\t.addColumn(\"seo_description\", \"text\")\n\t\t.addColumn(\"seo_image\", \"text\")\n\t\t.addColumn(\"seo_canonical\", \"text\")\n\t\t.addColumn(\"seo_no_index\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"_emdash_seo_pk\", [\"collection\", \"content_id\"])\n\t\t.execute();\n\n\t// Index for batch lookups by collection (PK covers point lookups).\n\t// Sitemap queries join on (collection, content_id) which the PK covers,\n\t// and filter seo_no_index. This index supports getMany() batch queries.\n\tawait sql`\n\t\tCREATE INDEX idx_emdash_seo_collection\n\t\tON _emdash_seo (collection)\n\t`.execute(db);\n\n\t// Add has_seo flag to collections\n\tawait sql`\n\t\tALTER TABLE _emdash_collections\n\t\tADD COLUMN has_seo INTEGER NOT NULL DEFAULT 0\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`DROP TABLE IF EXISTS _emdash_seo`.execute(db);\n\n\t// SQLite doesn't support DROP COLUMN before 3.35.0, but D1 does\n\tawait sql`\n\t\tALTER TABLE _emdash_collections\n\t\tDROP COLUMN has_seo\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite, listTablesLike } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * Migration: i18n support (row-per-locale model)\n *\n * Each piece of content can exist in multiple locales. Translations of the\n * same content share a `translation_group` ULID while each row carries its\n * own `locale` code. Slugs are unique per-locale, not globally.\n *\n * Changes:\n * 1. For every ec_* content table:\n * - Rebuild the table to replace inline `slug TEXT UNIQUE` with\n * `slug TEXT` + a compound `UNIQUE(slug, locale)` constraint.\n * - Add `locale TEXT NOT NULL DEFAULT 'en'`\n * - Add `translation_group TEXT`\n * - Backfill `translation_group = id` for existing rows\n * - Recreate all standard indexes plus new locale/translation_group indexes\n *\n * 2. Add `translatable` column to `_emdash_fields`\n *\n * The table-rebuild approach is required because SQLite cannot drop an inline\n * UNIQUE constraint via ALTER TABLE. We use PRAGMA table_info to discover all\n * columns (including dynamic user-defined fields) and rebuild dynamically.\n */\n\n// Column info returned by PRAGMA table_info\ninterface ColumnInfo {\n\tcid: number;\n\tname: string;\n\ttype: string;\n\tnotnull: number;\n\tdflt_value: string | null;\n\tpk: number;\n}\n\n// Index info returned by PRAGMA index_list\ninterface IndexInfo {\n\tseq: number;\n\tname: string;\n\tunique: number;\n\torigin: string;\n\tpartial: number;\n}\n\n// Index column info returned by PRAGMA index_info\ninterface IndexColumnInfo {\n\tseqno: number;\n\tcid: number;\n\tname: string;\n}\n\n/**\n * Quote an identifier for use in raw SQL. Escapes embedded double-quotes\n * per SQL standard (double them). The name should first pass\n * validateIdentifier() or validateTableName() for defense-in-depth.\n */\nconst DOUBLE_QUOTE_RE = /\"/g;\nfunction quoteIdent(name: string): string {\n\treturn `\"${name.replace(DOUBLE_QUOTE_RE, '\"\"')}\"`;\n}\n\n/** Suffix added to tmp tables during i18n migration rebuild. */\nconst I18N_TMP_SUFFIX = /_i18n_tmp$/;\n\n/** Table names from sqlite_master are ec_{slug} — validate the pattern. */\nconst TABLE_NAME_PATTERN = /^ec_[a-z][a-z0-9_]*$/;\nfunction validateTableName(name: string): void {\n\tif (!TABLE_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(`Invalid content table name: \"${name}\"`);\n\t}\n}\n\n/** SQLite column types produced by EmDash's schema registry. */\nconst ALLOWED_COLUMN_TYPES = new Set([\"TEXT\", \"INTEGER\", \"REAL\", \"BLOB\", \"JSON\", \"NUMERIC\", \"\"]);\nfunction validateColumnType(type: string, colName: string): void {\n\tif (!ALLOWED_COLUMN_TYPES.has(type.toUpperCase())) {\n\t\tthrow new Error(`Unexpected column type \"${type}\" for column \"${colName}\"`);\n\t}\n}\n\n/**\n * Validate that a default value expression from PRAGMA table_info is safe\n * to interpolate into DDL. Allows: string literals, numeric literals,\n * NULL, and known function calls like datetime('now').\n *\n * Note: PRAGMA table_info strips the outer parens from expression defaults,\n * so `DEFAULT (datetime('now'))` is reported as `datetime('now')`.\n * We accept both forms and re-wrap in parens via normalizeDdlDefault().\n */\nconst SAFE_DEFAULT_PATTERN =\n\t/^(?:'[^']*'|NULL|-?\\d+(?:\\.\\d+)?|\\(?datetime\\('now'\\)\\)?|\\(?json\\('[^']*'\\)\\)?|0|1)$/i;\nfunction validateDefaultValue(value: string, colName: string): void {\n\tif (!SAFE_DEFAULT_PATTERN.test(value)) {\n\t\tthrow new Error(`Unexpected default value \"${value}\" for column \"${colName}\"`);\n\t}\n}\n\n/**\n * Normalize a PRAGMA table_info default value for use in DDL.\n * Function-call defaults (e.g. `datetime('now')`) must be wrapped in parens\n * to form valid expression defaults: `DEFAULT (datetime('now'))`.\n * PRAGMA strips the outer parens, so we re-add them here.\n */\nconst FUNCTION_DEFAULT_PATTERN = /^(?:datetime|json)\\(/i;\nfunction normalizeDdlDefault(value: string): string {\n\t// Already wrapped in parens — return as-is\n\tif (value.startsWith(\"(\")) return value;\n\tif (FUNCTION_DEFAULT_PATTERN.test(value)) return `(${value})`;\n\treturn value;\n}\n\n/**\n * Validate that a CREATE INDEX statement from sqlite_master is safe to replay.\n * Must start with CREATE [UNIQUE] INDEX and not contain suspicious patterns.\n */\nconst CREATE_INDEX_PATTERN = /^CREATE\\s+(UNIQUE\\s+)?INDEX\\s+/i;\nfunction validateCreateIndexSql(sqlStr: string, idxName: string): void {\n\tif (!CREATE_INDEX_PATTERN.test(sqlStr)) {\n\t\tthrow new Error(`Unexpected index SQL for \"${idxName}\": does not match CREATE INDEX pattern`);\n\t}\n\t// Reject semicolons which could allow statement injection\n\tif (sqlStr.includes(\";\")) {\n\t\tthrow new Error(`Unexpected index SQL for \"${idxName}\": contains semicolon`);\n\t}\n}\n\n/**\n * PostgreSQL path: ALTER TABLE supports ADD COLUMN and DROP CONSTRAINT directly.\n * No table rebuild needed.\n */\nasync function upPostgres(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const t of tableNames) {\n\t\tvalidateTableName(t);\n\n\t\t// Check if already migrated (idempotency)\n\t\tconst hasLocale = await sql<{ exists: boolean }>`\n\t\t\tSELECT EXISTS(\n\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\tWHERE table_schema = current_schema() AND table_name = ${t} AND column_name = 'locale'\n\t\t\t) as exists\n\t\t`.execute(db);\n\t\tif (hasLocale.rows[0]?.exists === true) continue;\n\n\t\t// Add i18n columns\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} ADD COLUMN locale TEXT NOT NULL DEFAULT 'en'`.execute(db);\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} ADD COLUMN translation_group TEXT`.execute(db);\n\n\t\t// Drop existing unique constraint on slug (Postgres auto-names these)\n\t\t// Find the constraint name first\n\t\tconst constraints = await sql<{ conname: string }>`\n\t\t\tSELECT conname FROM pg_constraint\n\t\t\tWHERE conrelid = ${t}::regclass\n\t\t\tAND contype = 'u'\n\t\t\tAND array_length(conkey, 1) = 1\n\t\t\tAND conkey[1] = (\n\t\t\t\tSELECT attnum FROM pg_attribute\n\t\t\t\tWHERE attrelid = ${t}::regclass AND attname = 'slug'\n\t\t\t)\n\t\t`.execute(db);\n\n\t\tfor (const c of constraints.rows) {\n\t\t\tawait sql`ALTER TABLE ${sql.ref(t)} DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);\n\t\t}\n\n\t\t// Add compound unique constraint\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(t)}\n\t\t\tADD CONSTRAINT ${sql.ref(`${t}_slug_locale_unique`)} UNIQUE (slug, locale)\n\t\t`.execute(db);\n\n\t\t// Backfill translation_group\n\t\tawait sql`UPDATE ${sql.ref(t)} SET translation_group = id`.execute(db);\n\n\t\t// Create indexes\n\t\tawait sql`CREATE INDEX ${sql.ref(`idx_${t}_locale`)} ON ${sql.ref(t)} (locale)`.execute(db);\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${t}_translation_group`)}\n\t\t\tON ${sql.ref(t)} (translation_group)\n\t\t`.execute(db);\n\t}\n\n\t// Add translatable flag to fields table\n\tconst hasTranslatable = await sql<{ exists: boolean }>`\n\t\tSELECT EXISTS(\n\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\tWHERE table_schema = current_schema() AND table_name = '_emdash_fields' AND column_name = 'translatable'\n\t\t) as exists\n\t`.execute(db);\n\tif (hasTranslatable.rows[0]?.exists !== true) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_fields\n\t\t\tADD COLUMN translatable INTEGER NOT NULL DEFAULT 1\n\t\t`.execute(db);\n\t}\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!isSqlite(db)) {\n\t\treturn upPostgres(db);\n\t}\n\n\t// Clean up orphaned tmp tables from a previous partial run.\n\t// On D1 (no transactions), a crash mid-migration can leave these behind.\n\tconst orphanedTmps = await listTablesLike(db, \"ec_%_i18n_tmp\");\n\tfor (const tmpName of orphanedTmps) {\n\t\tvalidateTableName(tmpName.replace(I18N_TMP_SUFFIX, \"\"));\n\t\tawait sql`DROP TABLE IF EXISTS ${sql.ref(tmpName)}`.execute(db);\n\t}\n\n\t// Discover all ec_* content tables\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tconst tables = { rows: tableNames.map((name) => ({ name })) };\n\n\tfor (const table of tables.rows) {\n\t\tconst t = table.name;\n\t\tvalidateTableName(t);\n\t\tconst tmp = `${t}_i18n_tmp`;\n\n\t\t// Note: no transaction wrapper — D1 doesn't support transactions,\n\t\t// and file-backed SQLite is single-writer so crash-safety is\n\t\t// handled by the journal mode. The tmp table approach is already\n\t\t// crash-recoverable (orphaned tmp tables are harmless).\n\t\t{\n\t\t\tconst trx = db;\n\t\t\t// ── 1. Read existing column definitions ──────────────────────\n\t\t\tconst colResult = await sql<ColumnInfo>`\n\t\t\t\tPRAGMA table_info(${sql.ref(t)})\n\t\t\t`.execute(trx);\n\t\t\tconst columns = colResult.rows;\n\n\t\t\t// ── Idempotency: skip tables already migrated ───────────────\n\t\t\t// On D1, the migrator can't use transactions, so a partially-\n\t\t\t// applied migration may not be recorded. If the table already\n\t\t\t// has a `locale` column, it was already rebuilt — skip it.\n\t\t\tif (columns.some((col) => col.name === \"locale\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// ── 2. Read existing indexes (to recreate after rebuild) ─────\n\t\t\tconst idxResult = await sql<IndexInfo>`\n\t\t\t\tPRAGMA index_list(${sql.ref(t)})\n\t\t\t`.execute(trx);\n\n\t\t\t// Collect non-autoindex, non-primary-key indexes for recreation\n\t\t\tconst indexDefs: { name: string; unique: boolean; columns: string[]; partial: number }[] = [];\n\t\t\tfor (const idx of idxResult.rows) {\n\t\t\t\t// Skip autoindexes (created by inline UNIQUE) — we're removing them\n\t\t\t\tif (idx.origin === \"pk\" || idx.name.startsWith(\"sqlite_autoindex_\")) continue;\n\n\t\t\t\tconst idxColResult = await sql<IndexColumnInfo>`\n\t\t\t\t\tPRAGMA index_info(${sql.ref(idx.name)})\n\t\t\t\t`.execute(trx);\n\n\t\t\t\tindexDefs.push({\n\t\t\t\t\tname: idx.name,\n\t\t\t\t\tunique: idx.unique === 1,\n\t\t\t\t\tcolumns: idxColResult.rows.map((c) => c.name),\n\t\t\t\t\tpartial: idx.partial,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For partial indexes we need the original CREATE statement\n\t\t\tconst partialSqls = new Map<string, string>();\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\tif (idx.partial) {\n\t\t\t\t\tconst createResult = await sql<{ sql: string }>`\n\t\t\t\t\t\tSELECT sql FROM sqlite_master \n\t\t\t\t\t\tWHERE type = 'index' AND name = ${idx.name}\n\t\t\t\t\t`.execute(trx);\n\t\t\t\t\tif (createResult.rows[0]?.sql) {\n\t\t\t\t\t\tpartialSqls.set(idx.name, createResult.rows[0].sql);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ── 3. Build column defs for the new table ──────────────────\n\t\t\t// Validate all column names from PRAGMA before using them in raw SQL.\n\t\t\t// These originate from our own schema, but defense-in-depth matters.\n\t\t\tfor (const col of columns) {\n\t\t\t\tvalidateIdentifier(col.name, \"column name\");\n\t\t\t}\n\n\t\t\t// Replace slug's inline UNIQUE with a table-level UNIQUE(slug, locale)\n\t\t\tconst colDefs: string[] = [];\n\t\t\tconst colNames: string[] = [];\n\n\t\t\tfor (const col of columns) {\n\t\t\t\tvalidateColumnType(col.type || \"TEXT\", col.name);\n\t\t\t\tcolNames.push(quoteIdent(col.name));\n\t\t\t\tlet def = `${quoteIdent(col.name)} ${col.type || \"TEXT\"}`;\n\n\t\t\t\tif (col.pk) {\n\t\t\t\t\tdef += \" PRIMARY KEY\";\n\t\t\t\t} else if (col.name === \"slug\") {\n\t\t\t\t\t// Intentionally omit UNIQUE — compound unique below\n\t\t\t\t} else {\n\t\t\t\t\tif (col.notnull) def += \" NOT NULL\";\n\t\t\t\t}\n\n\t\t\t\tif (col.dflt_value !== null) {\n\t\t\t\t\tvalidateDefaultValue(col.dflt_value, col.name);\n\t\t\t\t\tdef += ` DEFAULT ${normalizeDdlDefault(col.dflt_value)}`;\n\t\t\t\t}\n\n\t\t\t\tcolDefs.push(def);\n\t\t\t}\n\n\t\t\t// Append new i18n columns\n\t\t\tcolDefs.push(\"\\\"locale\\\" TEXT NOT NULL DEFAULT 'en'\");\n\t\t\tcolDefs.push('\"translation_group\" TEXT');\n\n\t\t\t// Compound unique: same slug + locale must be unique\n\t\t\tcolDefs.push('UNIQUE(\"slug\", \"locale\")');\n\n\t\t\tconst createColsSql = colDefs.join(\",\\n\\t\\t\\t\\t\");\n\t\t\tconst selectColsSql = colNames.join(\", \");\n\n\t\t\t// ── 4. Rebuild the table ────────────────────────────────────\n\t\t\t// Drop all existing indexes first (they reference the old table)\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(idx.name)}`.execute(trx);\n\t\t\t}\n\n\t\t\t// Create new table with updated schema\n\t\t\tawait sql\n\t\t\t\t.raw(`CREATE TABLE ${quoteIdent(tmp)} (\\n\\t\\t\\t\\t${createColsSql}\\n\\t\\t\\t)`)\n\t\t\t\t.execute(trx);\n\n\t\t\t// Copy existing data, backfilling locale='en' and translation_group=id\n\t\t\tawait sql\n\t\t\t\t.raw(\n\t\t\t\t\t`INSERT INTO ${quoteIdent(tmp)} (${selectColsSql}, \"locale\", \"translation_group\")\\n\\t\\t\\t SELECT ${selectColsSql}, 'en', \"id\" FROM ${quoteIdent(t)}`,\n\t\t\t\t)\n\t\t\t\t.execute(trx);\n\n\t\t\t// Swap tables\n\t\t\tawait sql`DROP TABLE ${sql.ref(t)}`.execute(trx);\n\t\t\tawait sql.raw(`ALTER TABLE ${quoteIdent(tmp)} RENAME TO ${quoteIdent(t)}`).execute(trx);\n\n\t\t\t// ── 5. Recreate all original indexes ────────────────────────\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\t// Skip the old slug-only index — replaced by slug_locale below\n\t\t\t\tif (idx.name === `idx_${t}_slug`) continue;\n\n\t\t\t\tif (idx.partial && partialSqls.has(idx.name)) {\n\t\t\t\t\t// Partial indexes — validate the SQL before replaying\n\t\t\t\t\tconst idxSql = partialSqls.get(idx.name)!;\n\t\t\t\t\tvalidateCreateIndexSql(idxSql, idx.name);\n\t\t\t\t\tawait sql.raw(idxSql).execute(trx);\n\t\t\t\t} else {\n\t\t\t\t\t// Validate index column names before interpolation\n\t\t\t\t\tfor (const c of idx.columns) {\n\t\t\t\t\t\tvalidateIdentifier(c, \"index column name\");\n\t\t\t\t\t}\n\t\t\t\t\tconst cols = idx.columns.map((c) => quoteIdent(c)).join(\", \");\n\t\t\t\t\tconst unique = idx.unique ? \"UNIQUE \" : \"\";\n\t\t\t\t\tawait sql\n\t\t\t\t\t\t.raw(`CREATE ${unique}INDEX ${quoteIdent(idx.name)} ON ${quoteIdent(t)} (${cols})`)\n\t\t\t\t\t\t.execute(trx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ── 6. Create new i18n indexes ──────────────────────────────\n\t\t\t// slug_locale unique is handled by the table constraint above,\n\t\t\t// but we still want a regular slug index for non-locale-aware queries\n\t\t\tawait sql`\n\t\t\t\tCREATE INDEX ${sql.ref(`idx_${t}_slug`)} \n\t\t\t\tON ${sql.ref(t)} (slug)\n\t\t\t`.execute(trx);\n\n\t\t\tawait sql`\n\t\t\t\tCREATE INDEX ${sql.ref(`idx_${t}_locale`)} \n\t\t\t\tON ${sql.ref(t)} (locale)\n\t\t\t`.execute(trx);\n\n\t\t\tawait sql`\n\t\t\t\tCREATE INDEX ${sql.ref(`idx_${t}_translation_group`)} \n\t\t\t\tON ${sql.ref(t)} (translation_group)\n\t\t\t`.execute(trx);\n\t\t}\n\t}\n\n\t// ── 7. Add translatable flag to fields table ────────────────────\n\t// Guard against duplicate column — on D1 the migration may have\n\t// partially applied without being recorded (no transaction support).\n\tconst fieldCols = await sql<ColumnInfo>`\n\t\tPRAGMA table_info(_emdash_fields)\n\t`.execute(db);\n\tif (!fieldCols.rows.some((col) => col.name === \"translatable\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_fields \n\t\t\tADD COLUMN translatable INTEGER NOT NULL DEFAULT 1\n\t\t`.execute(db);\n\t}\n}\n\n/**\n * PostgreSQL down path: straightforward ALTER TABLE operations.\n */\nasync function downPostgres(db: Kysely<unknown>): Promise<void> {\n\tawait sql`ALTER TABLE _emdash_fields DROP COLUMN translatable`.execute(db);\n\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tfor (const t of tableNames) {\n\t\tvalidateTableName(t);\n\n\t\t// Drop i18n indexes\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${t}_locale`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${t}_translation_group`)}`.execute(db);\n\n\t\t// Drop compound unique constraint\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} DROP CONSTRAINT IF EXISTS ${sql.ref(`${t}_slug_locale_unique`)}`.execute(\n\t\t\tdb,\n\t\t);\n\n\t\t// Restore simple unique constraint on slug\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} ADD CONSTRAINT ${sql.ref(`${t}_slug_unique`)} UNIQUE (slug)`.execute(\n\t\t\tdb,\n\t\t);\n\n\t\t// Drop i18n columns\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} DROP COLUMN locale`.execute(db);\n\t\tawait sql`ALTER TABLE ${sql.ref(t)} DROP COLUMN translation_group`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (!isSqlite(db)) {\n\t\treturn downPostgres(db);\n\t}\n\n\t// Remove translatable column from fields table\n\tawait sql`\n\t\tALTER TABLE _emdash_fields\n\t\tDROP COLUMN translatable\n\t`.execute(db);\n\n\t// Discover all ec_* content tables\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst t = tableName;\n\t\tvalidateTableName(t);\n\t\tconst tmp = `${t}_i18n_tmp`;\n\n\t\t// No transaction — see comment in up() above.\n\t\t{\n\t\t\tconst trx = db;\n\t\t\t// ── 1. Read current column definitions ──────────────────────\n\t\t\tconst colResult = await sql<ColumnInfo>`\n\t\t\t\tPRAGMA table_info(${sql.ref(t)})\n\t\t\t`.execute(trx);\n\t\t\tconst columns = colResult.rows;\n\n\t\t\t// ── 2. Read current indexes ─────────────────────────────────\n\t\t\tconst idxResult = await sql<IndexInfo>`\n\t\t\t\tPRAGMA index_list(${sql.ref(t)})\n\t\t\t`.execute(trx);\n\n\t\t\tconst indexDefs: { name: string; unique: boolean; columns: string[]; partial: number }[] = [];\n\t\t\tfor (const idx of idxResult.rows) {\n\t\t\t\tif (idx.origin === \"pk\" || idx.name.startsWith(\"sqlite_autoindex_\")) continue;\n\n\t\t\t\tconst idxColResult = await sql<IndexColumnInfo>`\n\t\t\t\t\tPRAGMA index_info(${sql.ref(idx.name)})\n\t\t\t\t`.execute(trx);\n\n\t\t\t\tindexDefs.push({\n\t\t\t\t\tname: idx.name,\n\t\t\t\t\tunique: idx.unique === 1,\n\t\t\t\t\tcolumns: idxColResult.rows.map((c) => c.name),\n\t\t\t\t\tpartial: idx.partial,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Save partial index SQL\n\t\t\tconst partialSqls = new Map<string, string>();\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\tif (idx.partial) {\n\t\t\t\t\tconst createResult = await sql<{ sql: string }>`\n\t\t\t\t\t\tSELECT sql FROM sqlite_master \n\t\t\t\t\t\tWHERE type = 'index' AND name = ${idx.name}\n\t\t\t\t\t`.execute(trx);\n\t\t\t\t\tif (createResult.rows[0]?.sql) {\n\t\t\t\t\t\tpartialSqls.set(idx.name, createResult.rows[0].sql);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ── 3. Build column defs WITHOUT locale/translation_group ───\n\t\t\t// Validate all column names\n\t\t\tfor (const col of columns) {\n\t\t\t\tif (col.name === \"locale\" || col.name === \"translation_group\") continue;\n\t\t\t\tvalidateIdentifier(col.name, \"column name\");\n\t\t\t}\n\n\t\t\t// Restore slug's inline UNIQUE\n\t\t\tconst colDefs: string[] = [];\n\t\t\tconst colNames: string[] = [];\n\n\t\t\tfor (const col of columns) {\n\t\t\t\t// Skip i18n columns\n\t\t\t\tif (col.name === \"locale\" || col.name === \"translation_group\") continue;\n\n\t\t\t\tvalidateColumnType(col.type || \"TEXT\", col.name);\n\t\t\t\tcolNames.push(quoteIdent(col.name));\n\t\t\t\tlet def = `${quoteIdent(col.name)} ${col.type || \"TEXT\"}`;\n\n\t\t\t\tif (col.pk) {\n\t\t\t\t\tdef += \" PRIMARY KEY\";\n\t\t\t\t} else if (col.name === \"slug\") {\n\t\t\t\t\t// Restore inline UNIQUE\n\t\t\t\t\tdef += \" UNIQUE\";\n\t\t\t\t} else {\n\t\t\t\t\tif (col.notnull) def += \" NOT NULL\";\n\t\t\t\t}\n\n\t\t\t\tif (col.dflt_value !== null) {\n\t\t\t\t\tvalidateDefaultValue(col.dflt_value, col.name);\n\t\t\t\t\tdef += ` DEFAULT ${normalizeDdlDefault(col.dflt_value)}`;\n\t\t\t\t}\n\n\t\t\t\tcolDefs.push(def);\n\t\t\t}\n\n\t\t\tconst createColsSql = colDefs.join(\",\\n\\t\\t\\t\\t\");\n\t\t\tconst selectColsSql = colNames.join(\", \");\n\n\t\t\t// ── 4. Rebuild the table ────────────────────────────────────\n\t\t\t// Drop all existing indexes first\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(idx.name)}`.execute(trx);\n\t\t\t}\n\n\t\t\t// Create table with original schema (slug UNIQUE, no i18n columns)\n\t\t\tawait sql\n\t\t\t\t.raw(`CREATE TABLE ${quoteIdent(tmp)} (\\n\\t\\t\\t\\t${createColsSql}\\n\\t\\t\\t)`)\n\t\t\t\t.execute(trx);\n\n\t\t\t// Copy data — keep only one row per content item.\n\t\t\t// Prefer locale='en' rows. For items without an 'en' row, pick the\n\t\t\t// row with the smallest locale code (deterministic, unlike bare GROUP BY).\n\t\t\t// Handle NULL translation_group by treating each such row as its own group.\n\t\t\t// INSERT OR IGNORE skips any duplicate slugs from the fallback pass.\n\t\t\tawait sql\n\t\t\t\t.raw(\n\t\t\t\t\t`INSERT OR IGNORE INTO ${quoteIdent(tmp)} (${selectColsSql})\n\t\t\t SELECT ${selectColsSql} FROM ${quoteIdent(t)}\n\t\t\t WHERE \"locale\" = 'en'`,\n\t\t\t\t)\n\t\t\t\t.execute(trx);\n\n\t\t\tawait sql\n\t\t\t\t.raw(\n\t\t\t\t\t`INSERT OR IGNORE INTO ${quoteIdent(tmp)} (${selectColsSql})\n\t\t\t SELECT ${selectColsSql} FROM ${quoteIdent(t)}\n\t\t\t WHERE \"id\" NOT IN (SELECT \"id\" FROM ${quoteIdent(tmp)})\n\t\t\t AND \"id\" IN (\n\t\t\t\tSELECT \"id\" FROM ${quoteIdent(t)} AS t2\n\t\t\t\tWHERE t2.\"translation_group\" IS NOT NULL\n\t\t\t\tAND t2.\"locale\" = (\n\t\t\t\t\tSELECT MIN(t3.\"locale\") FROM ${quoteIdent(t)} AS t3\n\t\t\t\t\tWHERE t3.\"translation_group\" = t2.\"translation_group\"\n\t\t\t\t)\n\t\t\t )`,\n\t\t\t\t)\n\t\t\t\t.execute(trx);\n\n\t\t\t// Pick up any rows with NULL translation_group that weren't already copied\n\t\t\tawait sql\n\t\t\t\t.raw(\n\t\t\t\t\t`INSERT OR IGNORE INTO ${quoteIdent(tmp)} (${selectColsSql})\n\t\t\t SELECT ${selectColsSql} FROM ${quoteIdent(t)}\n\t\t\t WHERE \"id\" NOT IN (SELECT \"id\" FROM ${quoteIdent(tmp)})\n\t\t\t AND \"translation_group\" IS NULL`,\n\t\t\t\t)\n\t\t\t\t.execute(trx);\n\n\t\t\t// Swap tables\n\t\t\tawait sql`DROP TABLE ${sql.ref(t)}`.execute(trx);\n\t\t\tawait sql.raw(`ALTER TABLE ${quoteIdent(tmp)} RENAME TO ${quoteIdent(t)}`).execute(trx);\n\n\t\t\t// ── 5. Recreate indexes ─────────────────────────────────────\n\t\t\tfor (const idx of indexDefs) {\n\t\t\t\t// Skip i18n-specific indexes — they don't exist in the old schema\n\t\t\t\tif (idx.name === `idx_${t}_locale`) continue;\n\t\t\t\tif (idx.name === `idx_${t}_translation_group`) continue;\n\n\t\t\t\tif (idx.partial && partialSqls.has(idx.name)) {\n\t\t\t\t\t// Partial indexes — validate the SQL before replaying\n\t\t\t\t\tconst idxSql = partialSqls.get(idx.name)!;\n\t\t\t\t\tvalidateCreateIndexSql(idxSql, idx.name);\n\t\t\t\t\tawait sql.raw(idxSql).execute(trx);\n\t\t\t\t} else {\n\t\t\t\t\t// Filter out i18n columns from any index that might reference them\n\t\t\t\t\tconst cols = idx.columns.filter((c) => c !== \"locale\" && c !== \"translation_group\");\n\t\t\t\t\tif (cols.length === 0) continue;\n\n\t\t\t\t\t// Validate column names\n\t\t\t\t\tfor (const c of cols) {\n\t\t\t\t\t\tvalidateIdentifier(c, \"index column name\");\n\t\t\t\t\t}\n\t\t\t\t\tconst colsSql = cols.map((c) => quoteIdent(c)).join(\", \");\n\t\t\t\t\tconst unique = idx.unique ? \"UNIQUE \" : \"\";\n\t\t\t\t\tawait sql\n\t\t\t\t\t\t.raw(`CREATE ${unique}INDEX ${quoteIdent(idx.name)} ON ${quoteIdent(t)} (${colsSql})`)\n\t\t\t\t\t\t.execute(trx);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * Migration: URL pattern for collections\n *\n * Adds `url_pattern` column to `_emdash_collections` so each collection\n * can declare its own URL structure (e.g. \"/{slug}\" for pages, \"/blog/{slug}\"\n * for posts). Used for menu URL resolution, sitemaps, and path-based lookups.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE _emdash_collections\n\t\tADD COLUMN url_pattern TEXT\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE _emdash_collections\n\t\tDROP COLUMN url_pattern\n\t`.execute(db);\n}\n","import { type Kysely, sql } from \"kysely\";\n\n/**\n * Migration: Remove section categories\n *\n * Section categories had a complete backend but no UI to create or manage them.\n * Rather than building the missing UI for a feature with very little need at this stage,\n * we're removing the feature entirely.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Drop index before column — SQLite requires this order\n\tawait db.schema.dropIndex(\"idx_sections_category\").ifExists().execute();\n\n\tawait db.schema.alterTable(\"_emdash_sections\").dropColumn(\"category_id\").execute();\n\n\tawait db.schema.dropTable(\"_emdash_section_categories\").execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// Recreate section categories table\n\tawait db.schema\n\t\t.createTable(\"_emdash_section_categories\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))\n\t\t.execute();\n\n\t// Re-add category_id column to sections\n\tawait db.schema\n\t\t.alterTable(\"_emdash_sections\")\n\t\t.addColumn(\"category_id\", \"text\", (col) =>\n\t\t\tcol.references(\"_emdash_section_categories.id\").onDelete(\"set null\"),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_sections_category\")\n\t\t.on(\"_emdash_sections\")\n\t\t.columns([\"category_id\"])\n\t\t.execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * Migration: Add marketplace fields to _plugin_state\n *\n * Adds `source` and `marketplace_version` columns to track\n * whether a plugin was installed from config or marketplace,\n * and which marketplace version is installed.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// source: 'config' (declared in astro.config) or 'marketplace' (installed from registry)\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tADD COLUMN source TEXT NOT NULL DEFAULT 'config'\n\t`.execute(db);\n\n\t// marketplace_version: tracks installed version for update checking\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tADD COLUMN marketplace_version TEXT\n\t`.execute(db);\n\n\t// Index for efficient marketplace plugin queries on cold start\n\tawait sql`\n\t\tCREATE INDEX idx_plugin_state_source\n\t\tON _plugin_state (source)\n\t\tWHERE source = 'marketplace'\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tDROP INDEX IF EXISTS idx_plugin_state_source\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN marketplace_version\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN source\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * Migration: Add display metadata to _plugin_state\n *\n * Stores display_name and description for marketplace plugins\n * so the admin UI can show meaningful info without re-fetching\n * from the marketplace on every page load.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tADD COLUMN display_name TEXT\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tADD COLUMN description TEXT\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN description\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN display_name\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * Migration: Add placeholder columns to media table\n *\n * Stores blurhash and dominant_color for LQIP (Low Quality Image Placeholder)\n * support. Generated at upload time from image pixel data.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE media\n\t\tADD COLUMN blurhash TEXT\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE media\n\t\tADD COLUMN dominant_color TEXT\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tALTER TABLE media\n\t\tDROP COLUMN dominant_color\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE media\n\t\tDROP COLUMN blurhash\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Create OAuth clients table\n *\n * Implements the oauth_clients registry so that the authorization endpoint\n * can validate client_id and enforce a per-client redirect URI allowlist.\n *\n * Each client has a set of pre-registered redirect URIs (JSON array).\n * The authorize endpoint rejects any redirect_uri not in the client's list.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_oauth_clients\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey()) // Client ID (e.g. URL or opaque string)\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull()) // Human-readable name\n\t\t.addColumn(\"redirect_uris\", \"text\", (col) => col.notNull()) // JSON array of allowed redirect URIs\n\t\t.addColumn(\"scopes\", \"text\") // JSON array of allowed scopes (null = all)\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_oauth_clients\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Create cron tasks table for plugin scheduled tasks.\n *\n * Each plugin can register cron tasks (recurring or one-shot) which are\n * stored here and executed by the platform-specific scheduler.\n *\n * The `next_run_at` + `status` + `enabled` index drives the \"find overdue\n * tasks\" query used by CronExecutor.tick().\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_cron_tasks\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"plugin_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"task_name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"schedule\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"is_oneshot\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"data\", \"text\") // JSON\n\t\t.addColumn(\"next_run_at\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"last_run_at\", \"text\")\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"idle\"))\n\t\t.addColumn(\"locked_at\", \"text\")\n\t\t.addColumn(\"enabled\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"uq_cron_tasks_plugin_task\", [\"plugin_id\", \"task_name\"])\n\t\t.execute();\n\n\t// Equality columns first (enabled, status), then range column (next_run_at)\n\t// for optimal B-tree index usage in the tick query.\n\tawait db.schema\n\t\t.createIndex(\"idx_cron_tasks_due\")\n\t\t.on(\"_emdash_cron_tasks\")\n\t\t.columns([\"enabled\", \"status\", \"next_run_at\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_cron_tasks_plugin\")\n\t\t.on(\"_emdash_cron_tasks\")\n\t\t.column(\"plugin_id\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_cron_tasks\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Create the comments table\n\tawait db.schema\n\t\t.createTable(\"_emdash_comments\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"collection\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"parent_id\", \"text\", (col) =>\n\t\t\tcol.references(\"_emdash_comments.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"author_name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"author_email\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"author_url\", \"text\")\n\t\t.addColumn(\"author_user_id\", \"text\", (col) => col.references(\"users.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"body\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"pending\"))\n\t\t.addColumn(\"ip_hash\", \"text\")\n\t\t.addColumn(\"user_agent\", \"text\")\n\t\t.addColumn(\"moderation_metadata\", \"text\") // JSON\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Indexes\n\tawait db.schema\n\t\t.createIndex(\"idx_comments_content\")\n\t\t.on(\"_emdash_comments\")\n\t\t.columns([\"collection\", \"content_id\", \"status\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_comments_parent\")\n\t\t.on(\"_emdash_comments\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_comments_status\")\n\t\t.on(\"_emdash_comments\")\n\t\t.columns([\"status\", \"created_at\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_comments_author_email\")\n\t\t.on(\"_emdash_comments\")\n\t\t.column(\"author_email\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_comments_author_user\")\n\t\t.on(\"_emdash_comments\")\n\t\t.column(\"author_user_id\")\n\t\t.execute();\n\n\t// Add collection-level comment settings columns\n\tawait db.schema\n\t\t.alterTable(\"_emdash_collections\")\n\t\t.addColumn(\"comments_enabled\", \"integer\", (col) => col.defaultTo(0))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.alterTable(\"_emdash_collections\")\n\t\t.addColumn(\"comments_moderation\", \"text\", (col) => col.defaultTo(\"first_time\"))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.alterTable(\"_emdash_collections\")\n\t\t.addColumn(\"comments_closed_after_days\", \"integer\", (col) => col.defaultTo(90))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.alterTable(\"_emdash_collections\")\n\t\t.addColumn(\"comments_auto_approve_users\", \"integer\", (col) => col.defaultTo(1))\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_comments\").execute();\n\n\t// Note: SQLite doesn't support DROP COLUMN before 3.35.0.\n\t// For down migrations on the collection settings columns, the table\n\t// would need to be rebuilt. Skipping for simplicity in v0.\n}\n","import { sql, type Kysely } from \"kysely\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait sql`ALTER TABLE _emdash_comments DROP COLUMN author_url`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.alterTable(\"_emdash_comments\").addColumn(\"author_url\", \"text\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// Redirect rules table\n\tawait db.schema\n\t\t.createTable(\"_emdash_redirects\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"source\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"destination\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"type\", \"integer\", (col) => col.notNull().defaultTo(301))\n\t\t.addColumn(\"is_pattern\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"enabled\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t.addColumn(\"hits\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"last_hit_at\", \"text\")\n\t\t.addColumn(\"group_name\", \"text\")\n\t\t.addColumn(\"auto\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// Unique source for exact (non-pattern) rules\n\t// SQLite doesn't support partial indexes with WHERE on all versions,\n\t// so we use a regular index and enforce uniqueness in the application layer\n\tawait db.schema\n\t\t.createIndex(\"idx_redirects_source\")\n\t\t.on(\"_emdash_redirects\")\n\t\t.column(\"source\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_redirects_enabled\")\n\t\t.on(\"_emdash_redirects\")\n\t\t.column(\"enabled\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_redirects_group\")\n\t\t.on(\"_emdash_redirects\")\n\t\t.column(\"group_name\")\n\t\t.execute();\n\n\t// 404 log table\n\tawait db.schema\n\t\t.createTable(\"_emdash_404_log\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"path\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"referrer\", \"text\")\n\t\t.addColumn(\"user_agent\", \"text\")\n\t\t.addColumn(\"ip\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema.createIndex(\"idx_404_log_path\").on(\"_emdash_404_log\").column(\"path\").execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_404_log_created\")\n\t\t.on(\"_emdash_404_log\")\n\t\t.column(\"created_at\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_404_log\").execute();\n\tawait db.schema.dropTable(\"_emdash_redirects\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Widen scheduled publishing index\n *\n * The original partial index (013) only covered status='scheduled'.\n * Published posts can now have scheduled draft changes, so widen the\n * index to cover all rows where scheduled_at IS NOT NULL.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_scheduled`)}\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_scheduled`)}\n\t\t\tON ${sql.ref(table.name)} (scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_scheduled`)}\n\t\t`.execute(db);\n\n\t\t// Restore the original narrower index\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_scheduled`)}\n\t\t\tON ${sql.ref(table.name)} (scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL AND status = 'scheduled'\n\t\t`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { currentTimestamp, listTablesLike } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_bylines\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"display_name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"bio\", \"text\")\n\t\t.addColumn(\"avatar_media_id\", \"text\", (col) => col.references(\"media.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"website_url\", \"text\")\n\t\t.addColumn(\"user_id\", \"text\", (col) => col.references(\"users.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"is_guest\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait sql`\n\t\tCREATE UNIQUE INDEX ${sql.ref(\"idx_bylines_user_id_unique\")}\n\t\tON ${sql.ref(\"_emdash_bylines\")} (user_id)\n\t\tWHERE user_id IS NOT NULL\n\t`.execute(db);\n\n\tawait db.schema.createIndex(\"idx_bylines_slug\").on(\"_emdash_bylines\").column(\"slug\").execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_bylines_display_name\")\n\t\t.on(\"_emdash_bylines\")\n\t\t.column(\"display_name\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_content_bylines\")\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"collection_slug\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"byline_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_bylines.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"role_label\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"content_bylines_unique\", [\"collection_slug\", \"content_id\", \"byline_id\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_content\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.columns([\"collection_slug\", \"content_id\", \"sort_order\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_byline\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.column(\"byline_id\")\n\t\t.execute();\n\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tfor (const tableName of tableNames) {\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tADD COLUMN primary_byline_id TEXT\n\t\t`.execute(db);\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(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tfor (const tableName of tableNames) {\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_primary_byline`)}\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)}\n\t\t\tDROP COLUMN primary_byline_id\n\t\t`.execute(db);\n\t}\n\n\tawait db.schema.dropTable(\"_emdash_content_bylines\").execute();\n\tawait db.schema.dropTable(\"_emdash_bylines\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Migration: Rate limits table + device code polling tracking.\n *\n * 1. Create _emdash_rate_limits for database-backed rate limiting\n * of unauthenticated endpoints (device code, magic link, passkey).\n *\n * 2. Add last_polled_at column to _emdash_device_codes for\n * RFC 8628 slow_down enforcement.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// ── Rate limits table ────────────────────────────────────────────\n\tawait db.schema\n\t\t.createTable(\"_emdash_rate_limits\")\n\t\t.addColumn(\"key\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"window\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"count\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t.addPrimaryKeyConstraint(\"pk_rate_limits\", [\"key\", \"window\"])\n\t\t.execute();\n\n\t// Index on window for efficient cleanup of expired entries\n\tawait db.schema\n\t\t.createIndex(\"idx_rate_limits_window\")\n\t\t.on(\"_emdash_rate_limits\")\n\t\t.column(\"window\")\n\t\t.execute();\n\n\t// ── Device code polling tracking ─────────────────────────────────\n\tawait db.schema.alterTable(\"_emdash_device_codes\").addColumn(\"last_polled_at\", \"text\").execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_rate_limits\").execute();\n\n\t// SQLite doesn't support DROP COLUMN before 3.35.0, but since this is\n\t// dev-only (v0, no migrations in production), we accept the limitation.\n\tawait db.schema.alterTable(\"_emdash_device_codes\").dropColumn(\"last_polled_at\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Optimize content table indexes for D1 performance\n *\n * Addresses GitHub issue #131: Full table scans causing massive D1 row reads.\n *\n * Changes:\n * 1. Replaces single-column indexes with composite indexes on ec_* tables\n * 2. Adds partial indexes for _emdash_comments status counting\n *\n * Impact: Reduces D1 row reads by 90%+ for admin panel operations.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\t// Drop redundant single-column indexes that will be replaced by composites\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_status`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_created`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_deleted`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_updated`)}`.execute(db);\n\n\t\t// Composite index for listing queries: WHERE deleted_at IS NULL ORDER BY updated_at DESC\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table.name}_deleted_updated_id`)}\n\t\t\tON ${sql.ref(table.name)} (deleted_at, updated_at DESC, id DESC)\n\t\t`.execute(db);\n\n\t\t// Composite index for count-by-status queries: WHERE deleted_at IS NULL AND status = ?\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table.name}_deleted_status`)}\n\t\t\tON ${sql.ref(table.name)} (deleted_at, status)\n\t\t`.execute(db);\n\n\t\t// Composite index for created-at ordering: WHERE deleted_at IS NULL ORDER BY created_at DESC\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table.name}_deleted_created_id`)}\n\t\t\tON ${sql.ref(table.name)} (deleted_at, created_at DESC, id DESC)\n\t\t`.execute(db);\n\t}\n\n\t// Add partial indexes for efficient comment status counting\n\t// Each index contains only rows for one status, enabling fast COUNT queries\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS idx_comments_pending\n\t\tON _emdash_comments (id)\n\t\tWHERE status = 'pending'\n\t`.execute(db);\n\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS idx_comments_approved\n\t\tON _emdash_comments (id)\n\t\tWHERE status = 'approved'\n\t`.execute(db);\n\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS idx_comments_spam\n\t\tON _emdash_comments (id)\n\t\tWHERE status = 'spam'\n\t`.execute(db);\n\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS idx_comments_trash\n\t\tON _emdash_comments (id)\n\t\tWHERE status = 'trash'\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\t// Drop composite indexes\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_deleted_updated_id`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_deleted_status`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_deleted_created_id`)}`.execute(db);\n\n\t\t// Restore original single-column indexes\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_status`)}\n\t\t\tON ${sql.ref(table.name)} (status)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_created`)}\n\t\t\tON ${sql.ref(table.name)} (created_at)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_deleted`)}\n\t\t\tON ${sql.ref(table.name)} (deleted_at)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${table.name}_updated`)}\n\t\t\tON ${sql.ref(table.name)} (updated_at)\n\t\t`.execute(db);\n\t}\n\n\t// Drop partial indexes for comments\n\tawait sql`DROP INDEX IF EXISTS idx_comments_pending`.execute(db);\n\tawait sql`DROP INDEX IF EXISTS idx_comments_approved`.execute(db);\n\tawait sql`DROP INDEX IF EXISTS idx_comments_spam`.execute(db);\n\tawait sql`DROP INDEX IF EXISTS idx_comments_trash`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table.name}_deleted_published_id`)}\n\t\t\tON ${sql.ref(table.name)} (deleted_at, published_at DESC, id DESC)\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tconst table = { name: tableName };\n\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${table.name}_deleted_published_id`)}`.execute(\n\t\t\tdb,\n\t\t);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/**\n * Migration: Bounded 404 logging\n *\n * Hardens `_emdash_404_log` against unauthenticated DoS. Previously every 404\n * inserted a new row, so an attacker could grow the table without bound.\n *\n * Changes:\n * - Adds `hits` (default 1, NOT NULL)\n * - Adds `last_seen_at` (nullable; SQLite can't add NOT NULL with a\n * non-constant default to a populated table, so the column is nullable\n * at the schema level and backfilled from `created_at` for existing rows;\n * new inserts via `log404` always set it)\n * - Deduplicates existing rows by path, keeping the most recent row per\n * path and summing hits\n * - Adds a UNIQUE index on `path` so upsert semantics work\n */\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst hitsExists = await columnExists(db, \"_emdash_404_log\", \"hits\");\n\n\t// 1. Add columns.\n\tif (!hitsExists) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_404_log\")\n\t\t\t.addColumn(\"hits\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t\t.execute();\n\t}\n\n\t// SQLite won't accept a non-constant default when adding a NOT NULL column\n\t// to a table with existing rows, so backfill in two steps: add nullable,\n\t// populate, then rely on the application layer / future inserts to set it.\n\tif (!(await columnExists(db, \"_emdash_404_log\", \"last_seen_at\"))) {\n\t\tawait db.schema.alterTable(\"_emdash_404_log\").addColumn(\"last_seen_at\", \"text\").execute();\n\t}\n\n\t// Backfill last_seen_at from created_at for existing rows.\n\tawait sql`\n\t\tUPDATE _emdash_404_log\n\t\tSET last_seen_at = created_at\n\t\tWHERE last_seen_at IS NULL\n\t`.execute(db);\n\n\t// 2. Deduplicate existing rows by path.\n\t// For each path, roll up hits and pick the freshest last_seen_at onto\n\t// a single keeper row, then delete the non-keepers. Uses window\n\t// functions (ROW_NUMBER) so the dedup SQL is valid on both SQLite\n\t// (3.25+, 2018) and Postgres. The previous GROUP BY approach was\n\t// accepted by SQLite but invalid on Postgres because `id` wasn't in\n\t// the GROUP BY or wrapped in an aggregate.\n\tif (!hitsExists) {\n\t\tawait sql`\n\t\t\tWITH ranked AS (\n\t\t\t\tSELECT\n\t\t\t\t\tid,\n\t\t\t\t\tpath,\n\t\t\t\t\tROW_NUMBER() OVER (\n\t\t\t\t\t\tPARTITION BY path\n\t\t\t\t\t\tORDER BY created_at DESC, id DESC\n\t\t\t\t\t) AS rn,\n\t\t\t\t\tCOUNT(*) OVER (PARTITION BY path) AS path_count,\n\t\t\t\t\tMAX(created_at) OVER (PARTITION BY path) AS latest_created_at\n\t\t\t\tFROM _emdash_404_log\n\t\t\t)\n\t\t\tUPDATE _emdash_404_log\n\t\t\tSET\n\t\t\t\thits = (SELECT path_count FROM ranked WHERE ranked.id = _emdash_404_log.id),\n\t\t\t\tlast_seen_at = (SELECT latest_created_at FROM ranked WHERE ranked.id = _emdash_404_log.id)\n\t\t\tWHERE id IN (SELECT id FROM ranked WHERE rn = 1)\n\t\t`.execute(db);\n\n\t\t// Delete the non-keepers (every row except the freshest per path).\n\t\tawait sql`\n\t\t\tDELETE FROM _emdash_404_log\n\t\t\tWHERE id IN (\n\t\t\t\tSELECT id FROM (\n\t\t\t\t\tSELECT\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tROW_NUMBER() OVER (\n\t\t\t\t\t\t\tPARTITION BY path\n\t\t\t\t\t\t\tORDER BY created_at DESC, id DESC\n\t\t\t\t\t\t) AS rn\n\t\t\t\t\tFROM _emdash_404_log\n\t\t\t\t) AS ranked\n\t\t\t\tWHERE rn > 1\n\t\t\t)\n\t\t`.execute(db);\n\t}\n\n\t// 3. Add unique index on path for upsert semantics.\n\tawait db.schema\n\t\t.createIndex(\"idx_404_log_path_unique\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_404_log\")\n\t\t.column(\"path\")\n\t\t.unique()\n\t\t.execute();\n\n\t// Drop the old non-unique index; the unique one covers the same lookups.\n\tawait db.schema.dropIndex(\"idx_404_log_path\").ifExists().execute();\n\n\t// 4. Index on last_seen_at for eviction ordering.\n\tawait db.schema\n\t\t.createIndex(\"idx_404_log_last_seen\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_404_log\")\n\t\t.column(\"last_seen_at\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_404_log_last_seen\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx_404_log_path_unique\").ifExists().execute();\n\n\t// Restore the original non-unique path index.\n\tawait db.schema\n\t\t.createIndex(\"idx_404_log_path\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_404_log\")\n\t\t.column(\"path\")\n\t\t.execute();\n\n\tawait db.schema.alterTable(\"_emdash_404_log\").dropColumn(\"last_seen_at\").execute();\n\tawait db.schema.alterTable(\"_emdash_404_log\").dropColumn(\"hits\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { getI18nConfig } from \"../../i18n/config.js\";\nimport { currentTimestamp, isSqlite } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * i18n for menus + taxonomies. Adds `locale` + `translation_group` to system\n * tables and stores translation_groups (not row ids) in\n * `_emdash_menu_items.reference_id` and `content_taxonomies.taxonomy_id`.\n * Backfill locale and column DEFAULTs use the site's configured defaultLocale.\n */\n\nfunction getDefaultLocale(): string {\n\treturn getI18nConfig()?.defaultLocale ?? \"en\";\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst defaultLocale = getDefaultLocale();\n\n\tif (isSqlite(db)) {\n\t\t// Rebuild children before parents to drop FKs that would CASCADE\n\t\t// on D1. D1 enforces FKs but ignores `PRAGMA foreign_keys = OFF`\n\t\t// (the standard SQLite escape), and its replacement\n\t\t// `PRAGMA defer_foreign_keys = ON` only defers constraint\n\t\t// validation, not CASCADE actions — so DROP TABLE <parent> still\n\t\t// wipes child rows (#1021). The FKs have to be physically removed\n\t\t// before the drop.\n\t\t// - `content_taxonomies.taxonomy_id` → `taxonomies(id) ON DELETE CASCADE`\n\t\t// - `_emdash_menu_items.menu_id` → `_emdash_menus(id) ON DELETE CASCADE`\n\t\t// - `_emdash_menu_items.parent_id` → `_emdash_menu_items(id) ON DELETE CASCADE`\n\t\t// Both FKs on `_emdash_menu_items` are stripped during the rebuild.\n\t\t// The runtime (`MenuRepository.delete` / `setItems`) already\n\t\t// performs the child-delete explicitly, so the loss of the cascade\n\t\t// is invisible to callers.\n\t\tawait rebuildContentTaxonomies(db);\n\t\tawait rebuildMenuItems(db, defaultLocale);\n\t\tawait rebuildMenus(db, defaultLocale);\n\t\tawait rebuildTaxonomies(db, defaultLocale);\n\t\tawait rebuildTaxonomyDefs(db, defaultLocale);\n\t\tawait remapMenuItemRefs(db);\n\t\treturn;\n\t}\n\n\tawait pgWiden(db, \"_emdash_menus\", [\"name\"], [\"name\", \"locale\"], defaultLocale);\n\tawait pgWiden(db, \"_emdash_menu_items\", null, null, defaultLocale);\n\tawait pgWiden(db, \"taxonomies\", [\"name\", \"slug\"], [\"name\", \"slug\", \"locale\"], defaultLocale);\n\tawait pgWiden(db, \"_emdash_taxonomy_defs\", [\"name\"], [\"name\", \"locale\"], defaultLocale);\n\tawait pgRemapContentTaxonomies(db);\n\tawait remapMenuItemRefs(db);\n}\n\nasync function rebuildMenus(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tif (await hasColumn(db, \"_emdash_menus\", \"locale\")) return;\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_menus_new\"`).execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_menus_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.addUniqueConstraint(\"_emdash_menus_name_locale_unique\", [\"name\", \"locale\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_menus_new (id, name, label, created_at, updated_at, locale, translation_group)\n\t\tSELECT id, name, label, created_at, updated_at, ${defaultLocale}, id FROM _emdash_menus\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_menus\").execute();\n\tawait sql`ALTER TABLE _emdash_menus_new RENAME TO _emdash_menus`.execute(db);\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_menus_locale\")\n\t\t.on(\"_emdash_menus\")\n\t\t.column(\"locale\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_menus_translation_group\")\n\t\t.on(\"_emdash_menus\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n}\n\nasync function rebuildMenuItems(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\t// Full table rebuild rather than ALTER TABLE ADD COLUMN: this strips\n\t// the `menu_id` and `parent_id` FKs from migration 005 so the\n\t// subsequent `DROP TABLE _emdash_menus` can't cascade-wipe menu items\n\t// on D1 (#1021). The FKs were never load-bearing at runtime — D1\n\t// disables FK enforcement, and `MenuRepository` always deletes\n\t// children explicitly. Mirrors `rebuildContentTaxonomies` below.\n\tif (await hasColumn(db, \"_emdash_menu_items\", \"locale\")) return;\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_menu_items_new\"`).execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_menu_items_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"menu_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_id\", \"text\")\n\t\t.addColumn(\"sort_order\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"type\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"reference_collection\", \"text\")\n\t\t.addColumn(\"reference_id\", \"text\")\n\t\t.addColumn(\"custom_url\", \"text\")\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"title_attr\", \"text\")\n\t\t.addColumn(\"target\", \"text\")\n\t\t.addColumn(\"css_classes\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_menu_items_new (\n\t\t\tid, menu_id, parent_id, sort_order, type, reference_collection,\n\t\t\treference_id, custom_url, label, title_attr, target, css_classes,\n\t\t\tcreated_at, locale, translation_group\n\t\t)\n\t\tSELECT\n\t\t\tid, menu_id, parent_id, sort_order, type, reference_collection,\n\t\t\treference_id, custom_url, label, title_attr, target, css_classes,\n\t\t\tcreated_at, ${defaultLocale}, id\n\t\tFROM _emdash_menu_items\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_menu_items\").execute();\n\tawait sql`ALTER TABLE _emdash_menu_items_new RENAME TO _emdash_menu_items`.execute(db);\n\n\t// Indexes from migration 005 are dropped with the underlying table; recreate.\n\tawait db.schema\n\t\t.createIndex(\"idx_menu_items_menu\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.columns([\"menu_id\", \"sort_order\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_menu_items_parent\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_menu_items_locale\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.column(\"locale\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_menu_items_translation_group\")\n\t\t.on(\"_emdash_menu_items\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n}\n\nasync function rebuildTaxonomies(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tif (await hasColumn(db, \"taxonomies\", \"locale\")) return;\n\tawait sql.raw(`DROP TABLE IF EXISTS \"taxonomies_new\"`).execute(db);\n\tawait sql`DROP INDEX IF EXISTS idx_taxonomies_name`.execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"taxonomies_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_id\", \"text\")\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.addUniqueConstraint(\"taxonomies_name_slug_locale_unique\", [\"name\", \"slug\", \"locale\"])\n\t\t// Self-FK points at `taxonomies_new` (not `taxonomies`) so dropping\n\t\t// the old table doesn't fire ON DELETE SET NULL against parent_id\n\t\t// values on D1. SQLite's RENAME rewrites the FK target to the new\n\t\t// name automatically.\n\t\t.addForeignKeyConstraint(\n\t\t\t\"taxonomies_parent_fk\",\n\t\t\t[\"parent_id\"],\n\t\t\t\"taxonomies_new\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"set null\"),\n\t\t)\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO taxonomies_new (id, name, slug, label, parent_id, data, locale, translation_group)\n\t\tSELECT id, name, slug, label, parent_id, data, ${defaultLocale}, id FROM taxonomies\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"taxonomies\").execute();\n\tawait sql`ALTER TABLE taxonomies_new RENAME TO taxonomies`.execute(db);\n\n\tawait db.schema.createIndex(\"idx_taxonomies_name\").on(\"taxonomies\").column(\"name\").execute();\n\tawait db.schema.createIndex(\"idx_taxonomies_locale\").on(\"taxonomies\").column(\"locale\").execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_translation_group\")\n\t\t.on(\"taxonomies\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n\t// Dropping the old table dropped idx_taxonomies_parent (from 015); recreate\n\t// it here for parity with rebuildMenuItems/rebuildContentTaxonomies. Existing\n\t// installs recover it via migration 047.\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_parent\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n}\n\nasync function rebuildTaxonomyDefs(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tif (await hasColumn(db, \"_emdash_taxonomy_defs\", \"locale\")) return;\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_taxonomy_defs_new\"`).execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_taxonomy_defs_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label_singular\", \"text\")\n\t\t.addColumn(\"hierarchical\", \"integer\", (c) => c.defaultTo(0))\n\t\t.addColumn(\"collections\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.addUniqueConstraint(\"_emdash_taxonomy_defs_name_locale_unique\", [\"name\", \"locale\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_taxonomy_defs_new\n\t\t\t(id, name, label, label_singular, hierarchical, collections, created_at, locale, translation_group)\n\t\tSELECT id, name, label, label_singular, hierarchical, collections, created_at, ${defaultLocale}, id\n\t\tFROM _emdash_taxonomy_defs\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_taxonomy_defs\").execute();\n\tawait sql`ALTER TABLE _emdash_taxonomy_defs_new RENAME TO _emdash_taxonomy_defs`.execute(db);\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_taxonomy_defs_locale\")\n\t\t.on(\"_emdash_taxonomy_defs\")\n\t\t.column(\"locale\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_taxonomy_defs_translation_group\")\n\t\t.on(\"_emdash_taxonomy_defs\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n}\n\nasync function rebuildContentTaxonomies(db: Kysely<unknown>): Promise<void> {\n\t// Drops the FK so `taxonomy_id` can point at a translation_group rather\n\t// than a row id. Runs before `rebuildTaxonomies` so the drop is safe on D1.\n\t// No remap is needed here: `rebuildTaxonomies` later seeds `translation_group\n\t// = id` for every preserved row, so the row-id values we copy resolve as\n\t// translation_group references after the migration completes. This coupling\n\t// is load-bearing — if the translation_group seed ever changes, this needs\n\t// an explicit remap *after* `rebuildTaxonomies` runs.\n\tconst fks = await sql<{ id: number }>`PRAGMA foreign_key_list(content_taxonomies)`.execute(db);\n\tif (fks.rows.length > 0) {\n\t\tawait sql.raw(`DROP TABLE IF EXISTS \"content_taxonomies_new\"`).execute(db);\n\t\tawait db.schema\n\t\t\t.createTable(\"content_taxonomies_new\")\n\t\t\t.addColumn(\"collection\", \"text\", (c) => c.notNull())\n\t\t\t.addColumn(\"entry_id\", \"text\", (c) => c.notNull())\n\t\t\t.addColumn(\"taxonomy_id\", \"text\", (c) => c.notNull())\n\t\t\t.addPrimaryKeyConstraint(\"content_taxonomies_pk\", [\"collection\", \"entry_id\", \"taxonomy_id\"])\n\t\t\t.execute();\n\n\t\tawait sql`\n\t\t\tINSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)\n\t\t\tSELECT collection, entry_id, taxonomy_id FROM content_taxonomies\n\t\t`.execute(db);\n\n\t\tawait db.schema.dropTable(\"content_taxonomies\").execute();\n\t\tawait sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);\n\t}\n\n\t// Recreate the taxonomy_id index from migration 015 unconditionally, OUTSIDE\n\t// the FK-presence guard above. The rebuild both strips the FK and drops the\n\t// old table's indexes, but D1 auto-commits each DDL statement — so a first\n\t// run that failed after the drop leaves the table with no FK and no index.\n\t// The retry then finds zero FKs and skips the rebuild; if the index recreate\n\t// lived inside that guard it would never run and the index would be lost for\n\t// good (#1701). `IF NOT EXISTS` keeps this a no-op once present.\n\tawait sql`CREATE INDEX IF NOT EXISTS idx_content_taxonomies_term ON content_taxonomies(taxonomy_id)`.execute(\n\t\tdb,\n\t);\n}\n\nasync function remapMenuItemRefs(db: Kysely<unknown>): Promise<void> {\n\t// Items with `reference_collection IS NULL` are left untouched — the\n\t// runtime fallback in `menus/index.ts` resolves them by id.\n\tconst collections = await sql<{ slug: string }>`SELECT slug FROM _emdash_collections`.execute(db);\n\tfor (const { slug } of collections.rows) {\n\t\tvalidateIdentifier(slug, \"collection slug\");\n\t\tconst ec = sql.ref(`ec_${slug}`);\n\t\tawait sql`\n\t\t\tUPDATE _emdash_menu_items SET reference_id = (\n\t\t\t\tSELECT translation_group FROM ${ec} WHERE ${ec}.id = _emdash_menu_items.reference_id\n\t\t\t)\n\t\t\tWHERE reference_collection = ${slug} AND reference_id IS NOT NULL\n\t\t\t\tAND EXISTS (SELECT 1 FROM ${ec} WHERE ${ec}.id = _emdash_menu_items.reference_id)\n\t\t`.execute(db);\n\t}\n\tawait sql`\n\t\tUPDATE _emdash_menu_items SET reference_id = (\n\t\t\tSELECT translation_group FROM taxonomies WHERE taxonomies.id = _emdash_menu_items.reference_id\n\t\t)\n\t\tWHERE type = 'taxonomy' AND reference_id IS NOT NULL\n\t\t\tAND EXISTS (SELECT 1 FROM taxonomies WHERE taxonomies.id = _emdash_menu_items.reference_id)\n\t`.execute(db);\n}\n\nasync function pgWiden(\n\tdb: Kysely<unknown>,\n\ttable: string,\n\toldCols: string[] | null,\n\tnewCols: string[] | null,\n\tdefaultLocale: string,\n): Promise<void> {\n\tvalidateSystemIdent(table);\n\tconst ref = sql.ref(table);\n\tawait sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS locale TEXT NOT NULL DEFAULT ${sql.lit(defaultLocale)}`.execute(\n\t\tdb,\n\t);\n\tawait sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS translation_group TEXT`.execute(db);\n\tawait sql`UPDATE ${ref} SET translation_group = id WHERE translation_group IS NULL`.execute(db);\n\tawait sql`CREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table}_locale`)} ON ${ref} (locale)`.execute(\n\t\tdb,\n\t);\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${table}_translation_group`)} ON ${ref} (translation_group)\n\t`.execute(db);\n\n\tif (!oldCols || !newCols) return;\n\tfor (const c of [...oldCols, ...newCols]) validateSystemIdent(c);\n\tconst cons = await sql<{ conname: string }>`\n\t\tSELECT conname FROM pg_constraint c\n\t\tWHERE c.conrelid = ${table}::regclass AND c.contype = 'u'\n\t\t\tAND array_length(c.conkey, 1) = ${oldCols.length}\n\t\t\tAND (\n\t\t\t\tSELECT array_agg(a.attname ORDER BY pos.ord)\n\t\t\t\tFROM unnest(c.conkey) WITH ORDINALITY AS pos(attnum, ord)\n\t\t\t\tJOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = pos.attnum\n\t\t\t)::text[] = ${oldCols}::text[]\n\t`.execute(db);\n\tfor (const c of cons.rows) {\n\t\tawait sql`ALTER TABLE ${ref} DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);\n\t}\n\tconst cols = sql.join(\n\t\tnewCols.map((c) => sql.ref(c)),\n\t\tsql`, `,\n\t);\n\tawait sql`\n\t\tALTER TABLE ${ref}\n\t\tADD CONSTRAINT ${sql.ref(`${table}_${newCols.join(\"_\")}_unique`)} UNIQUE (${cols})\n\t`.execute(db);\n}\n\nasync function pgRemapContentTaxonomies(db: Kysely<unknown>): Promise<void> {\n\tconst fks = await sql<{ conname: string }>`\n\t\tSELECT conname FROM pg_constraint\n\t\tWHERE conrelid = 'content_taxonomies'::regclass AND contype = 'f'\n\t`.execute(db);\n\tfor (const c of fks.rows) {\n\t\tawait sql`ALTER TABLE content_taxonomies DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);\n\t}\n\tawait sql`\n\t\tUPDATE content_taxonomies SET taxonomy_id = t.translation_group\n\t\tFROM taxonomies t WHERE t.id = content_taxonomies.taxonomy_id\n\t`.execute(db);\n}\n\nasync function hasColumn(db: Kysely<unknown>, table: string, column: string): Promise<boolean> {\n\tconst rows = await sql<{ name: string }>`PRAGMA table_info(${sql.ref(table)})`.execute(db);\n\treturn rows.rows.some((r) => r.name === column);\n}\n\nconst SYSTEM_IDENT = /^[_a-z][a-z0-9_]*$/;\nfunction validateSystemIdent(name: string): void {\n\tif (!SYSTEM_IDENT.test(name)) throw new Error(`Invalid identifier: \"${name}\"`);\n}\n\n/**\n * down() restores the FK on content_taxonomies. Rows whose taxonomy_id doesn't\n * resolve to a (translation_group, defaultLocale) pair would fail the rebuild\n * after other tables are already stripped — leaving the user mid-rollback.\n * Surface dangling rows up front instead.\n */\nasync function assertContentTaxonomiesResolve(\n\tdb: Kysely<unknown>,\n\tdefaultLocale: string,\n): Promise<void> {\n\tconst result = await sql<{ count: number | string }>`\n\t\tSELECT COUNT(*) AS count FROM content_taxonomies ct\n\t\tWHERE NOT EXISTS (\n\t\t\tSELECT 1 FROM taxonomies t\n\t\t\tWHERE t.translation_group = ct.taxonomy_id AND t.locale = ${defaultLocale}\n\t\t)\n\t`.execute(db);\n\tconst count = Number(result.rows[0]?.count ?? 0);\n\tif (count > 0) {\n\t\tthrow new Error(\n\t\t\t`Cannot revert migration 036_i18n_menus_and_taxonomies: ` +\n\t\t\t\t`${count} row(s) in \"content_taxonomies\" reference a translation_group ` +\n\t\t\t\t`with no row in \"taxonomies\" at locale=\"${defaultLocale}\". ` +\n\t\t\t\t`Clean up the dangling associations before rolling back.`,\n\t\t);\n\t}\n}\n\n/**\n * down() is destructive on multi-locale installs (dropping `locale` collapses\n * translated rows onto an ambiguous unique key). Refuse to run when any row\n * sits at a locale other than the configured defaultLocale.\n */\nasync function assertSingleLocale(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tconst tables = [\"_emdash_menus\", \"_emdash_menu_items\", \"taxonomies\", \"_emdash_taxonomy_defs\"];\n\tfor (const table of tables) {\n\t\tvalidateSystemIdent(table);\n\t\tconst result = await sql<{ count: number | string }>`\n\t\t\tSELECT COUNT(*) AS count FROM ${sql.ref(table)} WHERE locale != ${defaultLocale}\n\t\t`.execute(db);\n\t\tconst count = Number(result.rows[0]?.count ?? 0);\n\t\tif (count > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot revert migration 036_i18n_menus_and_taxonomies: ` +\n\t\t\t\t\t`${count} row(s) in \"${table}\" use a non-default locale ` +\n\t\t\t\t\t`(defaultLocale=\"${defaultLocale}\"). ` +\n\t\t\t\t\t`Reverting would drop them silently. Export translations first ` +\n\t\t\t\t\t`(or delete them) and re-run the rollback. ` +\n\t\t\t\t\t`See packages/core/src/database/migrations/036_i18n_menus_and_taxonomies.ts.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst defaultLocale = getDefaultLocale();\n\tawait assertSingleLocale(db, defaultLocale);\n\tawait assertContentTaxonomiesResolve(db, defaultLocale);\n\n\tconst widenedTables = [\n\t\t\"_emdash_menus\",\n\t\t\"_emdash_menu_items\",\n\t\t\"taxonomies\",\n\t\t\"_emdash_taxonomy_defs\",\n\t];\n\n\tif (isSqlite(db)) {\n\t\t// Indexes first: the locale index on _emdash_menu_items would\n\t\t// otherwise block its DROP COLUMN.\n\t\tfor (const t of widenedTables) {\n\t\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_${t}_locale`).execute(db);\n\t\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_${t}_translation_group`).execute(db);\n\t\t}\n\n\t\t// Remap content_taxonomies values back to row ids while `taxonomies`\n\t\t// still has `translation_group` + `locale`. No FK is restored yet, so\n\t\t// the subsequent DROP TABLE taxonomies can't cascade on D1 (#1021).\n\t\tawait remapContentTaxonomiesDown(db, defaultLocale);\n\t\t// Menus first: safe because up() stripped the cascade FK from\n\t\t// _emdash_menu_items.menu_id, so dropping _emdash_menus doesn't\n\t\t// cascade. The FK from migration 005 is NOT restored on\n\t\t// _emdash_menu_items: the runtime deletes children explicitly,\n\t\t// so the only observable effect of the FK was the #1021 cascade\n\t\t// we're trying to avoid.\n\t\tawait rebuildMenusDown(db);\n\t\tawait rebuildMenuItemsDown(db);\n\t\tawait rebuildTaxonomiesDown(db);\n\t\tawait rebuildTaxonomyDefsDown(db);\n\t\tawait restoreContentTaxonomiesFk(db);\n\t\treturn;\n\t}\n\n\tfor (const t of widenedTables) {\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_${t}_locale`).execute(db);\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_${t}_translation_group`).execute(db);\n\t\tawait sql.raw(`ALTER TABLE \"${t}\" DROP COLUMN IF EXISTS locale`).execute(db);\n\t\tawait sql.raw(`ALTER TABLE \"${t}\" DROP COLUMN IF EXISTS translation_group`).execute(db);\n\t}\n}\n\nasync function remapContentTaxonomiesDown(\n\tdb: Kysely<unknown>,\n\tdefaultLocale: string,\n): Promise<void> {\n\t// Map translation_group back to row id (assertSingleLocale guarantees 1:1)\n\t// without restoring the FK — that happens after `taxonomies` is rebuilt.\n\tawait sql`\n\t\tUPDATE content_taxonomies\n\t\tSET taxonomy_id = COALESCE(\n\t\t\t(SELECT t.id FROM taxonomies t\n\t\t\t WHERE t.translation_group = content_taxonomies.taxonomy_id\n\t\t\t\t AND t.locale = ${defaultLocale}),\n\t\t\ttaxonomy_id\n\t\t)\n\t`.execute(db);\n}\n\nasync function restoreContentTaxonomiesFk(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"content_taxonomies_new\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"content_taxonomies_new\")\n\t\t.addColumn(\"collection\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"entry_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"taxonomy_id\", \"text\", (c) => c.notNull())\n\t\t.addPrimaryKeyConstraint(\"content_taxonomies_pk\", [\"collection\", \"entry_id\", \"taxonomy_id\"])\n\t\t.addForeignKeyConstraint(\n\t\t\t\"content_taxonomies_taxonomy_fk\",\n\t\t\t[\"taxonomy_id\"],\n\t\t\t\"taxonomies\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"cascade\"),\n\t\t)\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT OR IGNORE INTO content_taxonomies_new (collection, entry_id, taxonomy_id)\n\t\tSELECT collection, entry_id, taxonomy_id FROM content_taxonomies\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"content_taxonomies\").execute();\n\tawait sql`ALTER TABLE content_taxonomies_new RENAME TO content_taxonomies`.execute(db);\n\n\tawait sql`CREATE INDEX IF NOT EXISTS idx_content_taxonomies_term ON content_taxonomies(taxonomy_id)`.execute(\n\t\tdb,\n\t);\n}\n\nasync function rebuildMenusDown(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_menus_old\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"_emdash_menus_old\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\tawait sql`\n\t\tINSERT INTO _emdash_menus_old (id, name, label, created_at, updated_at)\n\t\tSELECT id, name, label, created_at, updated_at FROM _emdash_menus\n\t`.execute(db);\n\tawait db.schema.dropTable(\"_emdash_menus\").execute();\n\tawait sql`ALTER TABLE _emdash_menus_old RENAME TO _emdash_menus`.execute(db);\n}\n\nasync function rebuildMenuItemsDown(db: Kysely<unknown>): Promise<void> {\n\t// No UNIQUE on (locale,…) here, so DROP COLUMN suffices. The migration-005\n\t// FKs are NOT restored: up() removed them to fix #1021, and the runtime\n\t// already deletes child rows explicitly so the cascade isn't needed.\n\tawait sql.raw(`ALTER TABLE _emdash_menu_items DROP COLUMN locale`).execute(db);\n\tawait sql.raw(`ALTER TABLE _emdash_menu_items DROP COLUMN translation_group`).execute(db);\n}\n\nasync function rebuildTaxonomiesDown(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"taxonomies_old\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"taxonomies_old\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_id\", \"text\")\n\t\t.addColumn(\"data\", \"text\")\n\t\t.addUniqueConstraint(\"taxonomies_name_slug_unique\", [\"name\", \"slug\"])\n\t\t.addForeignKeyConstraint(\n\t\t\t\"taxonomies_parent_fk\",\n\t\t\t[\"parent_id\"],\n\t\t\t\"taxonomies_old\",\n\t\t\t[\"id\"],\n\t\t\t(cb) => cb.onDelete(\"set null\"),\n\t\t)\n\t\t.execute();\n\tawait sql`\n\t\tINSERT INTO taxonomies_old (id, name, slug, label, parent_id, data)\n\t\tSELECT id, name, slug, label, parent_id, data FROM taxonomies\n\t`.execute(db);\n\tawait db.schema.dropTable(\"taxonomies\").execute();\n\tawait sql`ALTER TABLE taxonomies_old RENAME TO taxonomies`.execute(db);\n\tawait db.schema.createIndex(\"idx_taxonomies_name\").on(\"taxonomies\").column(\"name\").execute();\n\t// Restore the pre-036 (migration 015) parent index so the rollback is faithful.\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_parent\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n}\n\nasync function rebuildTaxonomyDefsDown(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_taxonomy_defs_old\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"_emdash_taxonomy_defs_old\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"label_singular\", \"text\")\n\t\t.addColumn(\"hierarchical\", \"integer\", (c) => c.defaultTo(0))\n\t\t.addColumn(\"collections\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\tawait sql`\n\t\tINSERT INTO _emdash_taxonomy_defs_old\n\t\t\t(id, name, label, label_singular, hierarchical, collections, created_at)\n\t\tSELECT id, name, label, label_singular, hierarchical, collections, created_at\n\t\tFROM _emdash_taxonomy_defs\n\t`.execute(db);\n\tawait db.schema.dropTable(\"_emdash_taxonomy_defs\").execute();\n\tawait sql`ALTER TABLE _emdash_taxonomy_defs_old RENAME TO _emdash_taxonomy_defs`.execute(db);\n}\n","import { type Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"credentials\", \"algorithm\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"credentials\")\n\t\t\t.addColumn(\"algorithm\", \"integer\", (col) => col.notNull().defaultTo(-7))\n\t\t\t.execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"credentials\", \"algorithm\")) {\n\t\tawait db.schema.alterTable(\"credentials\").dropColumn(\"algorithm\").execute();\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite } from \"../dialect-helpers.js\";\n\ninterface ColumnInfo {\n\tname: string;\n}\n\ninterface IndexInfo {\n\tname: string;\n}\n\n/**\n * Migration: Add registry fields to _plugin_state\n *\n * Extends the marketplace columns added in 022 to support the\n * experimental decentralized plugin registry (see RFC #694). Rather\n * than introducing a separate `_registry_plugin_state` table, we\n * reuse the same row shape and distinguish registry installs via the\n * existing `source` column (now `'config' | 'marketplace' | 'registry'`).\n *\n * Registry plugins are addressed by `(publisher_did, slug)` in their\n * lexicon records but stored under a hashed, opaque `plugin_id` for\n * runtime compatibility -- see `packages/core/src/registry/plugin-id.ts`.\n * The `(publisher_did, slug)` pair is preserved here for update\n * resolution against the currently configured aggregator and for admin\n * UI rendering (\"by @example.dev\").\n *\n * All new columns are nullable; existing marketplace and config rows\n * keep working unchanged.\n *\n * Idempotency: D1 and SQLite don't honor the migration runner's\n * advisory lock, so a partial re-apply (cold start race between two\n * isolates, retry after a connection drop) can re-enter this `up`\n * function with the columns or index already in place. Each step\n * checks before adding to keep the migration safe under partial\n * re-application. The same pattern is used in 019_i18n.ts.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (isSqlite(db)) {\n\t\tawait upSqlite(db);\n\t} else {\n\t\tawait upPostgres(db);\n\t}\n}\n\nasync function upSqlite(db: Kysely<unknown>): Promise<void> {\n\tconst cols = await sql<ColumnInfo>`PRAGMA table_info(_plugin_state)`.execute(db);\n\tconst colNames = new Set(cols.rows.map((c) => c.name));\n\n\tif (!colNames.has(\"registry_publisher_did\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _plugin_state\n\t\t\tADD COLUMN registry_publisher_did TEXT\n\t\t`.execute(db);\n\t}\n\n\tif (!colNames.has(\"registry_slug\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _plugin_state\n\t\t\tADD COLUMN registry_slug TEXT\n\t\t`.execute(db);\n\t}\n\n\tconst indexes = await sql<IndexInfo>`PRAGMA index_list(_plugin_state)`.execute(db);\n\tconst indexNames = new Set(indexes.rows.map((i) => i.name));\n\n\tif (!indexNames.has(\"idx_plugin_state_registry\")) {\n\t\tawait sql`\n\t\t\tCREATE INDEX idx_plugin_state_registry\n\t\t\tON _plugin_state (source)\n\t\t\tWHERE source = 'registry'\n\t\t`.execute(db);\n\t}\n}\n\nasync function upPostgres(db: Kysely<unknown>): Promise<void> {\n\t// Scope the column check to the connection's current schema.\n\t// Without `table_schema = current_schema()`, a `_plugin_state` table\n\t// in another schema (per-tenant Postgres, shared Postgres clusters,\n\t// per-test schemas) makes this query see columns from the wrong\n\t// table and skip the ALTERs entirely, leaving the active schema's\n\t// `_plugin_state` missing the registry columns.\n\tconst cols = await sql<{ column_name: string }>`\n\t\tSELECT column_name FROM information_schema.columns\n\t\tWHERE table_name = '_plugin_state'\n\t\t AND table_schema = current_schema()\n\t`.execute(db);\n\tconst colNames = new Set(cols.rows.map((c) => c.column_name));\n\n\tif (!colNames.has(\"registry_publisher_did\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _plugin_state\n\t\t\tADD COLUMN registry_publisher_did TEXT\n\t\t`.execute(db);\n\t}\n\n\tif (!colNames.has(\"registry_slug\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _plugin_state\n\t\t\tADD COLUMN registry_slug TEXT\n\t\t`.execute(db);\n\t}\n\n\t// pg's CREATE INDEX IF NOT EXISTS handles the race natively; partial\n\t// index syntax differs from SQLite (`WHERE` is supported), so the\n\t// statement is otherwise identical.\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS idx_plugin_state_registry\n\t\tON _plugin_state (source)\n\t\tWHERE source = 'registry'\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tDROP INDEX IF EXISTS idx_plugin_state_registry\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN registry_slug\n\t`.execute(db);\n\n\tawait sql`\n\t\tALTER TABLE _plugin_state\n\t\tDROP COLUMN registry_publisher_did\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * Migration: Rebuild FTS5 indexes with corruption-safe triggers\n *\n * Background: FTS5 virtual tables created with `content='ec_<slug>'` are\n * *external content* tables. Pre-fix versions of EmDash used the\n * *contentless*-table sync pattern in their triggers\n * (`DELETE FROM fts WHERE rowid = OLD.rowid`), which is unsafe for\n * external-content FTS5 because FTS5 then reads the *current* row from\n * `ec_<slug>` to compute the tokens to remove. By the time\n * `AFTER UPDATE` fires the row already holds NEW values, so the wrong\n * tokens are removed and the inverted index drifts out of sync until\n * SQLite raises `SQLITE_CORRUPT_VTAB` on the next mutation\n * (see issue #649, PR #768).\n *\n * The fix that ships in the same release rewrites the triggers to use\n * the documented external-content-safe form:\n *\n * INSERT INTO fts(fts, rowid, col1, col2)\n * VALUES('delete', OLD.rowid, OLD.col1, OLD.col2);\n *\n * gated on `OLD.deleted_at IS NULL` so we don't try to remove rows that\n * were never indexed (which would itself raise `SQLITE_CORRUPT_VTAB`).\n *\n * This migration finalises the fix for *upgrading* sites. New triggers\n * alone are not enough: existing sites still carry the broken triggers in\n * `sqlite_master` and, in many cases, an already-corrupted FTS shadow\n * index. We:\n *\n * 1. Find every collection with FTS enabled\n * (`_emdash_collections.search_config -> enabled = true`).\n * 2. Drop its three sync triggers and the FTS5 virtual table itself\n * (which removes the shadow tables `<fts>_data`, `<fts>_idx`,\n * `<fts>_docsize`, `<fts>_config`, `<fts>_content`).\n * 3. Recreate the FTS5 table and triggers with the corruption-safe\n * `'delete'` form.\n * 4. Repopulate from `ec_<slug> WHERE deleted_at IS NULL`.\n *\n * The trigger SQL emitted here MUST stay in lock-step with\n * `FTSManager.createTriggers` in `src/search/fts-manager.ts`. The two\n * code paths build the same triggers from the same field list; keeping\n * them aligned means a fresh install (via FTSManager) and an upgraded\n * install (via this migration) end up with identical schemas. If\n * `createTriggers` ever changes again, add a new migration rather than\n * editing this one -- migrations are forward-only.\n *\n * Postgres: no-op. FTS5 is SQLite-only; the `FTSManager` already\n * short-circuits on non-SQLite, and there are no FTS tables to rebuild.\n *\n * D1: the migration is idempotent at the granularity we care about\n * (drop-then-create + repopulate). A partial re-apply that gets as far\n * as dropping the FTS table but not recreating it leaves the collection\n * without an index; the next runtime call to `verifyAndRepairIndex`\n * (e.g. on a search request) detects the missing table and rebuilds.\n * Re-running this migration in full is also safe -- it always replaces\n * the index from `ec_<slug>` content.\n */\n\ninterface CollectionRow {\n\tslug: string;\n\tsearch_config: string | null;\n}\n\ninterface FieldRow {\n\tslug: string;\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!isSqlite(db)) return;\n\n\tconst collections = await sql<CollectionRow>`\n\t\tSELECT slug, search_config FROM _emdash_collections\n\t\tWHERE search_config IS NOT NULL\n\t`.execute(db);\n\n\tfor (const collection of collections.rows) {\n\t\tif (!isSearchEnabled(collection.search_config)) continue;\n\n\t\t// Slug came from `_emdash_collections.slug`, where the schema\n\t\t// registry validates it against the same identifier rules on\n\t\t// write. Re-validate here defensively before interpolating it\n\t\t// into raw SQL -- this is a migration, so a malformed slug\n\t\t// that somehow landed in the DB must not become an injection\n\t\t// vector.\n\t\ttry {\n\t\t\tvalidateIdentifier(collection.slug, \"collection slug\");\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`[migration 039] skipping FTS rebuild for collection \"${collection.slug}\": ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fields = await getSearchableFields(db, collection.slug);\n\t\tif (fields.length === 0) {\n\t\t\t// `search_config.enabled = true` but no searchable fields:\n\t\t\t// disable search and drop any orphan FTS objects. This\n\t\t\t// matches FTSManager's \"no fields -> disable\" behavior.\n\t\t\tawait dropFtsObjects(db, collection.slug);\n\t\t\tawait sql`\n\t\t\t\tUPDATE _emdash_collections\n\t\t\t\tSET search_config = json_set(search_config, '$.enabled', json('false'))\n\t\t\t\tWHERE slug = ${collection.slug}\n\t\t\t`.execute(db);\n\t\t\tcontinue;\n\t\t}\n\n\t\tawait rebuildIndex(db, collection.slug, fields);\n\t}\n}\n\n/**\n * Forward-only migration. Down is a no-op: we cannot meaningfully\n * \"restore the broken triggers\" and there is no migration-level state\n * to roll back. The FTS tables themselves are managed by `FTSManager`\n * at runtime, not by this migration, so leaving them in their\n * corruption-safe state on rollback is correct.\n */\nexport async function down(_db: Kysely<unknown>): Promise<void> {\n\t// no-op\n}\n\nfunction isSearchEnabled(searchConfig: string | null): boolean {\n\tif (!searchConfig) return false;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(searchConfig);\n\t\treturn (\n\t\t\ttypeof parsed === \"object\" &&\n\t\t\tparsed !== null &&\n\t\t\t\"enabled\" in parsed &&\n\t\t\tparsed.enabled === true\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function getSearchableFields(db: Kysely<unknown>, collectionSlug: string): Promise<string[]> {\n\tconst rows = await sql<FieldRow>`\n\t\tSELECT f.slug FROM _emdash_fields f\n\t\tINNER JOIN _emdash_collections c ON c.id = f.collection_id\n\t\tWHERE c.slug = ${collectionSlug} AND f.searchable = 1\n\t`.execute(db);\n\n\tconst out: string[] = [];\n\tfor (const row of rows.rows) {\n\t\ttry {\n\t\t\tvalidateIdentifier(row.slug, \"searchable field name\");\n\t\t\tout.push(row.slug);\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t`[migration 039] skipping invalid searchable field \"${row.slug}\" on collection \"${collectionSlug}\"`,\n\t\t\t);\n\t\t}\n\t}\n\treturn out;\n}\n\nasync function rebuildIndex(\n\tdb: Kysely<unknown>,\n\tcollectionSlug: string,\n\tfields: string[],\n): Promise<void> {\n\tconst ftsTable = `_emdash_fts_${collectionSlug}`;\n\tconst contentTable = `ec_${collectionSlug}`;\n\tconst columnList = [\"id UNINDEXED\", \"locale UNINDEXED\", ...fields].join(\", \");\n\tconst fieldList = fields.join(\", \");\n\tconst newFieldList = fields.map((f) => `NEW.${f}`).join(\", \");\n\tconst oldFieldList = fields.map((f) => `OLD.${f}`).join(\", \");\n\n\tawait dropFtsObjects(db, collectionSlug);\n\n\t// `IF NOT EXISTS` on every CREATE so concurrent migrators on D1\n\t// (no advisory lock, see runner.ts:264) converge instead of one\n\t// failing the other. Duplicate-rowid INSERTs into an external-\n\t// content FTS5 table dedupe via the docsize shadow table, so a\n\t// double populate ends with one row per content row. The brief\n\t// window between DROP and CREATE where another isolate could fire\n\t// a trigger against a missing FTS table is pre-existing -- it also\n\t// exists in FTSManager.rebuildIndex at runtime.\n\tawait sql\n\t\t.raw(`\n\t\tCREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTable}\" USING fts5(\n\t\t\t${columnList},\n\t\t\tcontent='${contentTable}',\n\t\t\tcontent_rowid='rowid',\n\t\t\ttokenize='porter unicode61'\n\t\t)\n\t`)\n\t\t.execute(db);\n\n\t// Insert trigger -- only index non-deleted content.\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_insert\"\n\t\tAFTER INSERT ON \"${contentTable}\"\n\t\tWHEN NEW.deleted_at IS NULL\n\t\tBEGIN\n\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tVALUES (NEW.rowid, NEW.id, NEW.locale, ${newFieldList});\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\t// Update trigger -- corruption-safe external-content `'delete'` form,\n\t// gated on OLD.deleted_at IS NULL so we never issue `'delete'` for a\n\t// rowid that was never indexed.\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_update\"\n\t\tAFTER UPDATE ON \"${contentTable}\"\n\t\tBEGIN\n\t\t\tINSERT INTO \"${ftsTable}\"(\"${ftsTable}\", rowid, id, locale, ${fieldList})\n\t\t\tSELECT 'delete', OLD.rowid, OLD.id, OLD.locale, ${oldFieldList}\n\t\t\tWHERE OLD.deleted_at IS NULL;\n\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tSELECT NEW.rowid, NEW.id, NEW.locale, ${newFieldList}\n\t\t\tWHERE NEW.deleted_at IS NULL;\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\t// Delete trigger -- same corruption-safe form, same gate.\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_delete\"\n\t\tAFTER DELETE ON \"${contentTable}\"\n\t\tBEGIN\n\t\t\tINSERT INTO \"${ftsTable}\"(\"${ftsTable}\", rowid, id, locale, ${fieldList})\n\t\t\tSELECT 'delete', OLD.rowid, OLD.id, OLD.locale, ${oldFieldList}\n\t\t\tWHERE OLD.deleted_at IS NULL;\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\t// Populate from existing content (non-deleted rows only). Concurrent\n\t// re-population is safe -- FTS5 INSERT into an external-content table\n\t// dedupes by rowid; a second pass over the same content rows leaves\n\t// the index with one entry per row, matching what we'd get from a\n\t// single populate.\n\tawait sql\n\t\t.raw(`\n\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\tSELECT rowid, id, locale, ${fieldList} FROM \"${contentTable}\"\n\t\tWHERE deleted_at IS NULL\n\t`)\n\t\t.execute(db);\n}\n\nasync function dropFtsObjects(db: Kysely<unknown>, collectionSlug: string): Promise<void> {\n\tconst ftsTable = `_emdash_fts_${collectionSlug}`;\n\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_insert\"`).execute(db);\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_update\"`).execute(db);\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_delete\"`).execute(db);\n\tawait sql.raw(`DROP TABLE IF EXISTS \"${ftsTable}\"`).execute(db);\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { getI18nConfig } from \"../../i18n/config.js\";\nimport { currentTimestamp, isSqlite, listTablesLike } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * i18n for bylines. Adds `locale` + `translation_group` to `_emdash_bylines`\n * and stores translation_groups (not row ids) in\n * `_emdash_content_bylines.byline_id` and `ec_*.primary_byline_id`. Backfill\n * locale and column DEFAULTs use the site's configured defaultLocale.\n *\n * Mirrors the row-per-locale + `translation_group` model PR #916 (migration\n * 036) applied to menus and taxonomies.\n *\n * Key consequences of the model:\n * - `(slug, locale)` is unique on `_emdash_bylines`; a single slug can repeat\n * across locales (one row per locale variant of a byline).\n * - The partial unique on `user_id` widens to `(user_id, locale)` so a CMS\n * user can have one byline per locale.\n * - `_emdash_content_bylines.byline_id` no longer FKs to `_emdash_bylines.id`\n * (it holds a `translation_group`, not a row id). The runtime is\n * responsible for cascading on byline delete — see `BylineRepository.delete`.\n *\n * Hydration is strict per locale (see `BylineRepository.getContentBylines`):\n * a credit at locale X renders iff a byline row exists at locale X within the\n * credited translation group. This mirrors `getEntryTerms` and the convention\n * established by #916. There is no read-time fallback.\n */\n\nfunction getDefaultLocale(): string {\n\treturn getI18nConfig()?.defaultLocale ?? \"en\";\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst defaultLocale = getDefaultLocale();\n\n\tif (isSqlite(db)) {\n\t\t// Rebuild children before parents to drop FKs that would CASCADE\n\t\t// on D1 (#1021). `_emdash_content_bylines.byline_id` has an FK to\n\t\t// `_emdash_bylines(id) ON DELETE CASCADE` from migration 031.\n\t\t// Stripping it first lets us rebuild `_emdash_bylines` without\n\t\t// risking a cascading wipe of credits on D1.\n\t\tawait rebuildContentBylines(db);\n\t\tawait rebuildBylines(db, defaultLocale);\n\t\tawait remapPrimaryBylineIds(db);\n\t\treturn;\n\t}\n\n\tawait pgWidenBylines(db, defaultLocale);\n\tawait pgDropContentBylinesFk(db);\n\tawait remapPrimaryBylineIds(db);\n}\n\nasync function rebuildContentBylines(db: Kysely<unknown>): Promise<void> {\n\t// Drops the FK so `byline_id` can point at a translation_group rather\n\t// than a row id. Runs before `rebuildBylines` so the drop is safe on D1.\n\t// No remap is needed here: `rebuildBylines` later seeds `translation_group\n\t// = id` for every preserved row, so the row-id values we copy resolve as\n\t// translation_group references after the migration completes. This coupling\n\t// is load-bearing — if the translation_group seed ever changes, this needs\n\t// an explicit remap *after* `rebuildBylines` runs.\n\tconst fks = await sql<{ id: number }>`PRAGMA foreign_key_list(_emdash_content_bylines)`.execute(\n\t\tdb,\n\t);\n\tif (fks.rows.length === 0) return;\n\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_content_bylines_new\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"_emdash_content_bylines_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"collection_slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"byline_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"sort_order\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"role_label\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"content_bylines_unique\", [\"collection_slug\", \"content_id\", \"byline_id\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_content_bylines_new\n\t\t\t(id, collection_slug, content_id, byline_id, sort_order, role_label, created_at)\n\t\tSELECT id, collection_slug, content_id, byline_id, sort_order, role_label, created_at\n\t\tFROM _emdash_content_bylines\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_content_bylines\").execute();\n\tawait sql`ALTER TABLE _emdash_content_bylines_new RENAME TO _emdash_content_bylines`.execute(db);\n\n\t// Indexes from migration 031 dropped with the table; restore.\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_content\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.columns([\"collection_slug\", \"content_id\", \"sort_order\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_byline\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.column(\"byline_id\")\n\t\t.execute();\n}\n\nasync function rebuildBylines(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tif (await hasColumn(db, \"_emdash_bylines\", \"locale\")) return;\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_bylines_new\"`).execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_bylines_new\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"display_name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"bio\", \"text\")\n\t\t.addColumn(\"avatar_media_id\", \"text\", (c) => c.references(\"media.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"website_url\", \"text\")\n\t\t.addColumn(\"user_id\", \"text\", (c) => c.references(\"users.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"is_guest\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.addUniqueConstraint(\"_emdash_bylines_slug_locale_unique\", [\"slug\", \"locale\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_bylines_new (\n\t\t\tid, slug, display_name, bio, avatar_media_id, website_url,\n\t\t\tuser_id, is_guest, created_at, updated_at, locale, translation_group\n\t\t)\n\t\tSELECT\n\t\t\tid, slug, display_name, bio, avatar_media_id, website_url,\n\t\t\tuser_id, is_guest, created_at, updated_at, ${defaultLocale}, id\n\t\tFROM _emdash_bylines\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_bylines\").execute();\n\tawait sql`ALTER TABLE _emdash_bylines_new RENAME TO _emdash_bylines`.execute(db);\n\n\t// Indexes from migration 031 dropped with the table; restore the\n\t// per-slug and per-display-name indexes. The partial unique on\n\t// user_id widens to (user_id, locale) so one CMS user can own one\n\t// byline per locale.\n\tawait db.schema.createIndex(\"idx_bylines_slug\").on(\"_emdash_bylines\").column(\"slug\").execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_bylines_display_name\")\n\t\t.on(\"_emdash_bylines\")\n\t\t.column(\"display_name\")\n\t\t.execute();\n\tawait sql`\n\t\tCREATE UNIQUE INDEX ${sql.ref(\"idx_bylines_user_id_locale_unique\")}\n\t\tON ${sql.ref(\"_emdash_bylines\")} (user_id, locale)\n\t\tWHERE user_id IS NOT NULL\n\t`.execute(db);\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_bylines_locale\")\n\t\t.on(\"_emdash_bylines\")\n\t\t.column(\"locale\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_bylines_translation_group\")\n\t\t.on(\"_emdash_bylines\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n\n\t// One row per (translation_group, locale): the row-per-locale model\n\t// (PR #916) requires that each locale variant of a byline appears\n\t// exactly once in its translation group. `UNIQUE(slug, locale)` doesn't\n\t// catch the case where two siblings in the same group use different\n\t// slugs at the same locale — this partial unique does. `WHERE\n\t// translation_group IS NOT NULL` is defensive: post-040 every row has a\n\t// value, but the column is nullable in the schema.\n\tawait sql`\n\t\tCREATE UNIQUE INDEX ${sql.ref(\"idx_bylines_group_locale_unique\")}\n\t\tON ${sql.ref(\"_emdash_bylines\")} (translation_group, locale)\n\t\tWHERE translation_group IS NOT NULL\n\t`.execute(db);\n}\n\nasync function remapPrimaryBylineIds(db: Kysely<unknown>): Promise<void> {\n\t// Walks every `ec_*` table and remaps `primary_byline_id` (row id →\n\t// translation_group). On a fresh install translation_group equals id\n\t// for every row, so the values look unchanged — but the column\n\t// semantics flip from \"FK to _emdash_bylines.id\" to \"translation_group\n\t// in _emdash_bylines.translation_group\". Once translations exist, the\n\t// remap is meaningful: a credit pointing at the en-row id still\n\t// resolves to the same byline group at every locale variant.\n\tconst collections = await listTablesLike(db, \"ec_%\");\n\tfor (const table of collections) {\n\t\tvalidateIdentifier(table, \"content table\");\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(table)} SET primary_byline_id = (\n\t\t\t\tSELECT translation_group FROM _emdash_bylines\n\t\t\t\tWHERE _emdash_bylines.id = ${sql.ref(table)}.primary_byline_id\n\t\t\t)\n\t\t\tWHERE primary_byline_id IS NOT NULL\n\t\t\t\tAND EXISTS (\n\t\t\t\t\tSELECT 1 FROM _emdash_bylines\n\t\t\t\t\tWHERE _emdash_bylines.id = ${sql.ref(table)}.primary_byline_id\n\t\t\t\t)\n\t\t`.execute(db);\n\t}\n}\n\nasync function pgWidenBylines(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tconst ref = sql.ref(\"_emdash_bylines\");\n\tawait sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS locale TEXT NOT NULL DEFAULT ${sql.lit(defaultLocale)}`.execute(\n\t\tdb,\n\t);\n\tawait sql`ALTER TABLE ${ref} ADD COLUMN IF NOT EXISTS translation_group TEXT`.execute(db);\n\tawait sql`UPDATE ${ref} SET translation_group = id WHERE translation_group IS NULL`.execute(db);\n\tawait sql`CREATE INDEX IF NOT EXISTS ${sql.ref(\"idx__emdash_bylines_locale\")} ON ${ref} (locale)`.execute(\n\t\tdb,\n\t);\n\tawait sql`\n\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(\"idx__emdash_bylines_translation_group\")}\n\t\tON ${ref} (translation_group)\n\t`.execute(db);\n\n\t// Widen UNIQUE(slug) -> UNIQUE(slug, locale)\n\tconst slugCons = await sql<{ conname: string }>`\n\t\tSELECT conname FROM pg_constraint c\n\t\tWHERE c.conrelid = '_emdash_bylines'::regclass AND c.contype = 'u'\n\t\t\tAND array_length(c.conkey, 1) = 1\n\t\t\tAND (\n\t\t\t\tSELECT array_agg(a.attname ORDER BY pos.ord)\n\t\t\t\tFROM unnest(c.conkey) WITH ORDINALITY AS pos(attnum, ord)\n\t\t\t\tJOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = pos.attnum\n\t\t\t)::text[] = ARRAY['slug']\n\t`.execute(db);\n\tfor (const c of slugCons.rows) {\n\t\tawait sql`ALTER TABLE ${ref} DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(db);\n\t}\n\tawait sql`\n\t\tALTER TABLE ${ref}\n\t\tADD CONSTRAINT _emdash_bylines_slug_locale_unique UNIQUE (slug, locale)\n\t`.execute(db);\n\n\t// Replace the partial unique on (user_id) with (user_id, locale).\n\tawait sql`DROP INDEX IF EXISTS idx_bylines_user_id_unique`.execute(db);\n\tawait sql`\n\t\tCREATE UNIQUE INDEX IF NOT EXISTS ${sql.ref(\"idx_bylines_user_id_locale_unique\")}\n\t\tON ${ref} (user_id, locale) WHERE user_id IS NOT NULL\n\t`.execute(db);\n\n\t// One row per (translation_group, locale): see SQLite branch above.\n\tawait sql`\n\t\tCREATE UNIQUE INDEX IF NOT EXISTS ${sql.ref(\"idx_bylines_group_locale_unique\")}\n\t\tON ${ref} (translation_group, locale) WHERE translation_group IS NOT NULL\n\t`.execute(db);\n}\n\nasync function pgDropContentBylinesFk(db: Kysely<unknown>): Promise<void> {\n\tconst fks = await sql<{ conname: string }>`\n\t\tSELECT conname FROM pg_constraint\n\t\tWHERE conrelid = '_emdash_content_bylines'::regclass AND contype = 'f'\n\t`.execute(db);\n\tfor (const c of fks.rows) {\n\t\tawait sql`ALTER TABLE _emdash_content_bylines DROP CONSTRAINT ${sql.ref(c.conname)}`.execute(\n\t\t\tdb,\n\t\t);\n\t}\n}\n\nasync function hasColumn(db: Kysely<unknown>, table: string, column: string): Promise<boolean> {\n\tconst rows = await sql<{ name: string }>`PRAGMA table_info(${sql.ref(table)})`.execute(db);\n\treturn rows.rows.some((r) => r.name === column);\n}\n\n/**\n * down() restores the FK on `_emdash_content_bylines.byline_id`. Rows whose\n * `byline_id` doesn't resolve to a (translation_group, defaultLocale) row in\n * `_emdash_bylines` would fail the rebuild after other tables are already\n * stripped — leaving the user mid-rollback. Surface dangling rows up front.\n */\nasync function assertContentBylinesResolve(\n\tdb: Kysely<unknown>,\n\tdefaultLocale: string,\n): Promise<void> {\n\tconst result = await sql<{ count: number | string }>`\n\t\tSELECT COUNT(*) AS count FROM _emdash_content_bylines cb\n\t\tWHERE NOT EXISTS (\n\t\t\tSELECT 1 FROM _emdash_bylines b\n\t\t\tWHERE b.translation_group = cb.byline_id AND b.locale = ${defaultLocale}\n\t\t)\n\t`.execute(db);\n\tconst count = Number(result.rows[0]?.count ?? 0);\n\tif (count > 0) {\n\t\tthrow new Error(\n\t\t\t`Cannot revert migration 040_byline_i18n: ` +\n\t\t\t\t`${count} row(s) in \"_emdash_content_bylines\" reference a translation_group ` +\n\t\t\t\t`with no row in \"_emdash_bylines\" at locale=\"${defaultLocale}\". ` +\n\t\t\t\t`Clean up the dangling credits before rolling back.`,\n\t\t);\n\t}\n}\n\n/**\n * down() is destructive on multi-locale installs (dropping `locale` collapses\n * translated rows onto an ambiguous unique key). Refuse to run when any row\n * sits at a locale other than the configured defaultLocale.\n */\nasync function assertSingleLocale(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tconst result = await sql<{ count: number | string }>`\n\t\tSELECT COUNT(*) AS count FROM _emdash_bylines WHERE locale != ${defaultLocale}\n\t`.execute(db);\n\tconst count = Number(result.rows[0]?.count ?? 0);\n\tif (count > 0) {\n\t\tthrow new Error(\n\t\t\t`Cannot revert migration 040_byline_i18n: ` +\n\t\t\t\t`${count} row(s) in \"_emdash_bylines\" use a non-default locale ` +\n\t\t\t\t`(defaultLocale=\"${defaultLocale}\"). ` +\n\t\t\t\t`Reverting would drop them silently. Export translations first ` +\n\t\t\t\t`(or delete them) and re-run the rollback. ` +\n\t\t\t\t`See packages/core/src/database/migrations/040_byline_i18n.ts.`,\n\t\t);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst defaultLocale = getDefaultLocale();\n\tawait assertSingleLocale(db, defaultLocale);\n\tawait assertContentBylinesResolve(db, defaultLocale);\n\n\tif (isSqlite(db)) {\n\t\t// Indexes first to avoid blocking the table rebuilds.\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx__emdash_bylines_locale`).execute(db);\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx__emdash_bylines_translation_group`).execute(db);\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_bylines_user_id_locale_unique`).execute(db);\n\t\tawait sql.raw(`DROP INDEX IF EXISTS idx_bylines_group_locale_unique`).execute(db);\n\n\t\t// Remap `_emdash_content_bylines.byline_id` and `ec_*.primary_byline_id`\n\t\t// from translation_group back to the row id of the defaultLocale\n\t\t// anchor. assertSingleLocale guarantees the mapping is 1:1, so the\n\t\t// rebuilt FK can validate every reference.\n\t\tawait remapPrimaryBylineIdsDown(db, defaultLocale);\n\t\tawait remapContentBylinesDown(db, defaultLocale);\n\n\t\t// Now safe to rebuild `_emdash_bylines` (strips locale +\n\t\t// translation_group, restores UNIQUE(slug) and the partial unique\n\t\t// on user_id alone).\n\t\tawait rebuildBylinesDown(db);\n\t\t// And finally restore the FK on `_emdash_content_bylines.byline_id`.\n\t\tawait restoreContentBylinesFk(db);\n\t\treturn;\n\t}\n\n\tawait remapPrimaryBylineIdsDown(db, defaultLocale);\n\tawait sql`\n\t\tUPDATE _emdash_content_bylines\n\t\tSET byline_id = COALESCE(\n\t\t\t(SELECT b.id FROM _emdash_bylines b\n\t\t\t WHERE b.translation_group = _emdash_content_bylines.byline_id\n\t\t\t\t AND b.locale = ${defaultLocale}),\n\t\t\tbyline_id\n\t\t)\n\t`.execute(db);\n\n\tawait sql.raw(`DROP INDEX IF EXISTS idx__emdash_bylines_locale`).execute(db);\n\tawait sql.raw(`DROP INDEX IF EXISTS idx__emdash_bylines_translation_group`).execute(db);\n\tawait sql.raw(`DROP INDEX IF EXISTS idx_bylines_user_id_locale_unique`).execute(db);\n\tawait sql.raw(`DROP INDEX IF EXISTS idx_bylines_group_locale_unique`).execute(db);\n\tawait sql\n\t\t.raw(\n\t\t\t`ALTER TABLE \"_emdash_bylines\" DROP CONSTRAINT IF EXISTS _emdash_bylines_slug_locale_unique`,\n\t\t)\n\t\t.execute(db);\n\tawait sql.raw(`ALTER TABLE \"_emdash_bylines\" DROP COLUMN IF EXISTS locale`).execute(db);\n\tawait sql\n\t\t.raw(`ALTER TABLE \"_emdash_bylines\" DROP COLUMN IF EXISTS translation_group`)\n\t\t.execute(db);\n\tawait sql\n\t\t.raw(`ALTER TABLE \"_emdash_bylines\" ADD CONSTRAINT _emdash_bylines_slug_unique UNIQUE (slug)`)\n\t\t.execute(db);\n\tawait sql`\n\t\tCREATE UNIQUE INDEX IF NOT EXISTS ${sql.ref(\"idx_bylines_user_id_unique\")}\n\t\tON _emdash_bylines (user_id) WHERE user_id IS NOT NULL\n\t`.execute(db);\n\tawait sql`\n\t\tALTER TABLE _emdash_content_bylines\n\t\tADD CONSTRAINT _emdash_content_bylines_byline_fk\n\t\tFOREIGN KEY (byline_id) REFERENCES _emdash_bylines(id) ON DELETE CASCADE\n\t`.execute(db);\n}\n\nasync function remapPrimaryBylineIdsDown(\n\tdb: Kysely<unknown>,\n\tdefaultLocale: string,\n): Promise<void> {\n\tconst collections = await listTablesLike(db, \"ec_%\");\n\tfor (const table of collections) {\n\t\tvalidateIdentifier(table, \"content table\");\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(table)}\n\t\t\tSET primary_byline_id = COALESCE(\n\t\t\t\t(SELECT b.id FROM _emdash_bylines b\n\t\t\t\t WHERE b.translation_group = ${sql.ref(table)}.primary_byline_id\n\t\t\t\t\t AND b.locale = ${defaultLocale}),\n\t\t\t\tprimary_byline_id\n\t\t\t)\n\t\t\tWHERE primary_byline_id IS NOT NULL\n\t\t`.execute(db);\n\t}\n}\n\nasync function remapContentBylinesDown(db: Kysely<unknown>, defaultLocale: string): Promise<void> {\n\tawait sql`\n\t\tUPDATE _emdash_content_bylines\n\t\tSET byline_id = COALESCE(\n\t\t\t(SELECT b.id FROM _emdash_bylines b\n\t\t\t WHERE b.translation_group = _emdash_content_bylines.byline_id\n\t\t\t\t AND b.locale = ${defaultLocale}),\n\t\t\tbyline_id\n\t\t)\n\t`.execute(db);\n}\n\nasync function rebuildBylinesDown(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_bylines_old\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"_emdash_bylines_old\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (c) => c.notNull().unique())\n\t\t.addColumn(\"display_name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"bio\", \"text\")\n\t\t.addColumn(\"avatar_media_id\", \"text\", (c) => c.references(\"media.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"website_url\", \"text\")\n\t\t.addColumn(\"user_id\", \"text\", (c) => c.references(\"users.id\").onDelete(\"set null\"))\n\t\t.addColumn(\"is_guest\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\tawait sql`\n\t\tINSERT INTO _emdash_bylines_old (\n\t\t\tid, slug, display_name, bio, avatar_media_id, website_url,\n\t\t\tuser_id, is_guest, created_at, updated_at\n\t\t)\n\t\tSELECT\n\t\t\tid, slug, display_name, bio, avatar_media_id, website_url,\n\t\t\tuser_id, is_guest, created_at, updated_at\n\t\tFROM _emdash_bylines\n\t`.execute(db);\n\tawait db.schema.dropTable(\"_emdash_bylines\").execute();\n\tawait sql`ALTER TABLE _emdash_bylines_old RENAME TO _emdash_bylines`.execute(db);\n\n\t// Restore the indexes that existed pre-040.\n\tawait db.schema.createIndex(\"idx_bylines_slug\").on(\"_emdash_bylines\").column(\"slug\").execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_bylines_display_name\")\n\t\t.on(\"_emdash_bylines\")\n\t\t.column(\"display_name\")\n\t\t.execute();\n\tawait sql`\n\t\tCREATE UNIQUE INDEX ${sql.ref(\"idx_bylines_user_id_unique\")}\n\t\tON ${sql.ref(\"_emdash_bylines\")} (user_id)\n\t\tWHERE user_id IS NOT NULL\n\t`.execute(db);\n}\n\nasync function restoreContentBylinesFk(db: Kysely<unknown>): Promise<void> {\n\tawait sql.raw(`DROP TABLE IF EXISTS \"_emdash_content_bylines_old\"`).execute(db);\n\tawait db.schema\n\t\t.createTable(\"_emdash_content_bylines_old\")\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"collection_slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"byline_id\", \"text\", (c) =>\n\t\t\tc.notNull().references(\"_emdash_bylines.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"sort_order\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"role_label\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"content_bylines_unique\", [\"collection_slug\", \"content_id\", \"byline_id\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_content_bylines_old\n\t\t\t(id, collection_slug, content_id, byline_id, sort_order, role_label, created_at)\n\t\tSELECT id, collection_slug, content_id, byline_id, sort_order, role_label, created_at\n\t\tFROM _emdash_content_bylines\n\t`.execute(db);\n\n\tawait db.schema.dropTable(\"_emdash_content_bylines\").execute();\n\tawait sql`ALTER TABLE _emdash_content_bylines_old RENAME TO _emdash_content_bylines`.execute(db);\n\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_content\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.columns([\"collection_slug\", \"content_id\", \"sort_order\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_byline\")\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.column(\"byline_id\")\n\t\t.execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: locale-aware composite indexes for content list queries.\n *\n * Addresses GitHub issue #1219. When i18n is enabled the admin content list\n * filters by `locale` and orders by `updated_at`/`created_at`. The existing\n * composite indexes (033/034) cover `(deleted_at, updated_at DESC, id DESC)`\n * etc. but omit `locale`, so a locale-filtered ordered list can't be served\n * by a single index on large tables. These indexes restore index-only paging\n * for the locale-scoped case.\n *\n * Forward-only and idempotent (`IF NOT EXISTS`).\n *\n * Index names use a short `loc_upd`/`loc_crt` suffix rather than spelling out\n * `deleted_locale_updated_id`: Postgres truncates identifiers to 63 bytes, and\n * the longer form pushes the `updated`/`created` discriminator past byte 63 for\n * slugs as short as 40 chars, making both names truncate to the same string.\n * Keep these identical to the names in `schema/registry.ts`.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${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(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${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(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_loc_upd`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_loc_crt`)}`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Byline custom fields (Discussion #1174). Adds three tables and a\n * version-counter row in `options`. Purely additive: no change to\n * `_emdash_bylines` columns landed by migration 040, no change to\n * `_emdash_content_bylines`.\n *\n * Storage model (D11 in the design spec):\n *\n * - `_emdash_byline_fields` — definitions. One row per registered field.\n * - `_emdash_byline_field_values` — translatable values, keyed by\n * `(byline_id, field_id)`. One value per locale variant of a byline.\n * - `_emdash_byline_field_group_values` — non-translatable values, keyed\n * by `(translation_group, field_id)`. One value shared across every\n * locale variant of the byline's translation group.\n *\n * The per-field `translatable` flag (column on `_emdash_byline_fields`)\n * decides which value table a field writes to. The split is at the\n * storage level rather than per-row so a single SELECT … IN per locale\n * bucket suffices for batched hydration (see Phase 3 of the PR plan).\n *\n * `options('byline_fields_version', '0')` is the version counter the\n * field-definitions cache reads (Phase 3). Every mutation on\n * `_emdash_byline_fields` bumps this row; cached defs invalidate on a\n * mismatch. Storing it in `options` (the same table `settings/index.ts`\n * uses) means we get the request-cache + persisted-version pattern for\n * free — no new infrastructure.\n *\n * Idempotency: every `CREATE TABLE` and `CREATE INDEX` uses\n * `.ifNotExists()`, so a partial prior run (a crash mid-migration, retried\n * after the runner's race-recovery path or after a manual fix) re-applies\n * cleanly — including any indexes that landed in the failed pass after the\n * table itself. A coarse table-level guard would skip the index step if the\n * table existed but indexes didn't (the realistic crash window between\n * `CREATE TABLE` and the next `CREATE INDEX`). The runner records applied\n * migrations only after a successful pass, so a crashed-then-retried `up()`\n * is the normal recovery path here.\n *\n * D1 has no transactions — the schema builder and `INSERT` for the\n * version row execute one statement at a time. Order matters: parent\n * tables first (`_emdash_byline_fields`), then the value tables that\n * reference it. If `down()` runs after a partial `up()`, missing tables\n * are tolerated (`DROP TABLE IF EXISTS`).\n */\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_byline_fields\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"slug\", \"text\", (col) => col.notNull().unique())\n\t\t.addColumn(\"label\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"type\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"required\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"translatable\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t.addColumn(\"validation\", \"text\") // JSON: { options?: string[] }\n\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_byline_fields_sort_order\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_byline_fields\")\n\t\t.column(\"sort_order\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_byline_field_values\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"byline_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_bylines.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"field_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_byline_fields.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"value\", \"text\") // JSON-encoded CustomFieldValue\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"_emdash_byline_field_values_pk\", [\"byline_id\", \"field_id\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_byline_field_values_byline\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_byline_field_values\")\n\t\t.column(\"byline_id\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_byline_field_values_field\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_byline_field_values\")\n\t\t.column(\"field_id\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_byline_field_group_values\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"translation_group\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"field_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_byline_fields.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"value\", \"text\") // JSON-encoded CustomFieldValue\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"_emdash_byline_field_group_values_pk\", [\n\t\t\t\"translation_group\",\n\t\t\t\"field_id\",\n\t\t])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_byline_field_group_values_group\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_byline_field_group_values\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_byline_field_group_values_field\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_byline_field_group_values\")\n\t\t.column(\"field_id\")\n\t\t.execute();\n\n\t// Version-counter row read by the field-definitions cache (Phase 3).\n\t// `options.value` stores JSON, so the initial counter is the JSON literal\n\t// `0`. `INSERT … ON CONFLICT DO NOTHING` so a retry after a crash that\n\t// landed the row but failed later in the migration does not double-insert.\n\tawait sql`\n\t\tINSERT INTO options (name, value) VALUES ('byline_fields_version', '0')\n\t\tON CONFLICT (name) DO NOTHING\n\t`.execute(db);\n}\n\n/**\n * Reverses the schema additions and removes the version-counter row.\n * Used by the test suite and by `rollbackMigration`; the runner itself\n * never invokes `down()` automatically.\n *\n * The drops are unconditional `IF EXISTS` so a `down()` after a partial\n * `up()` (only one or two tables landed) still settles the database back\n * to its pre-042 state.\n */\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\t// Child tables first to avoid FK reference issues on Postgres. SQLite +\n\t// D1 accept either order with `IF EXISTS`, but explicit ordering keeps\n\t// the dialects parity-safe.\n\tawait db.schema.dropTable(\"_emdash_byline_field_group_values\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_byline_field_values\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_byline_fields\").ifExists().execute();\n\tawait sql`DELETE FROM options WHERE name = 'byline_fields_version'`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\n\nimport { getI18nConfig } from \"../../i18n/config.js\";\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Content references.\n *\n * `_emdash_relations` defines relationship types (row-per-locale, mirroring\n * `_emdash_taxonomy_defs`): which collection is the parent, which is the child\n * (the side that may multiply), and localized labels for each role.\n *\n * `_emdash_content_references` holds directed `parent → child` edges between\n * content entries. Both endpoints and the relation are referenced by\n * `translation_group`, so edges are locale-agnostic. As with\n * `content_taxonomies`, group-linking precludes SQL foreign keys; referential\n * cleanup is an application-layer concern.\n *\n * Idempotency: every `CREATE TABLE` and `CREATE INDEX` uses `.ifNotExists()`,\n * so a partial prior run (a crash mid-migration, or a retry after the runner's\n * race-recovery path) re-applies cleanly — including any indexes that landed in\n * the failed pass after their table.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst defaultLocale = getI18nConfig()?.defaultLocale ?? \"en\";\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_relations\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_collection\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"child_collection\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"child_label\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"locale\", \"text\", (c) => c.notNull().defaultTo(defaultLocale))\n\t\t.addColumn(\"translation_group\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"_emdash_relations_name_locale_unique\", [\"name\", \"locale\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_relations_locale\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_relations\")\n\t\t.column(\"locale\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_relations_translation_group\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_relations\")\n\t\t.column(\"translation_group\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_relations_parent_collection\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_relations\")\n\t\t.column(\"parent_collection\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_relations_child_collection\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_relations\")\n\t\t.column(\"child_collection\")\n\t\t.execute();\n\n\t// One row per (translation_group, locale): the row-per-locale model wants a\n\t// relation to have at most one variant per locale. Migration 040 enforces\n\t// the same invariant for `_emdash_bylines` with a *partial* unique\n\t// (`WHERE translation_group IS NOT NULL`) only because it back-fills an\n\t// existing table; this table is new and `translation_group` is `NOT NULL`,\n\t// so a plain unique index suffices.\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_relations_group_locale_unique\")\n\t\t.ifNotExists()\n\t\t.unique()\n\t\t.on(\"_emdash_relations\")\n\t\t.columns([\"translation_group\", \"locale\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_content_references\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"relation_group\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"parent_group\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"child_group\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"sort_order\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"content_references_unique\", [\n\t\t\t\"relation_group\",\n\t\t\t\"parent_group\",\n\t\t\t\"child_group\",\n\t\t])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_content_references_parent\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_content_references\")\n\t\t.columns([\"parent_group\", \"relation_group\", \"sort_order\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_content_references_child\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_content_references\")\n\t\t.columns([\"child_group\", \"relation_group\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_content_references_relation\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_content_references\")\n\t\t.column(\"relation_group\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_content_references\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_relations\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Comment reactions (Tier 1 of the best-in-class comments RFC).\n *\n * One row per (comment, voter, reaction). Toggle semantics are enforced by the\n * unique index — a voter either has a given reaction on a comment or doesn't.\n * `voter_hash` is a salted SHA-256 of the visitor's IP (same primitive as\n * `_emdash_comments.ip_hash`), so no cleartext identity is stored.\n *\n * Additive and backward-compatible: a new table, no change to existing schema.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_comment_reactions\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"comment_id\", \"text\", (col) =>\n\t\t\tcol.notNull().references(\"_emdash_comments.id\").onDelete(\"cascade\"),\n\t\t)\n\t\t.addColumn(\"reaction\", \"text\", (col) => col.notNull().defaultTo(\"like\"))\n\t\t.addColumn(\"voter_hash\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\t// One reaction of a given type per voter per comment (toggle semantics).\n\tawait db.schema\n\t\t.createIndex(\"idx_comment_reactions_unique\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_comment_reactions\")\n\t\t.columns([\"comment_id\", \"voter_hash\", \"reaction\"])\n\t\t.unique()\n\t\t.execute();\n\n\t// Aggregate counts per comment (GROUP BY comment_id, reaction).\n\tawait db.schema\n\t\t.createIndex(\"idx_comment_reactions_comment\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_comment_reactions\")\n\t\t.column(\"comment_id\")\n\t\t.execute();\n\n\t// Per-voter rate limiting (recent reactions by a voter).\n\tawait db.schema\n\t\t.createIndex(\"idx_comment_reactions_voter\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_comment_reactions\")\n\t\t.columns([\"voter_hash\", \"created_at\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_comment_reactions\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\n/**\n * Store the parent's `translation_group` in `taxonomies.parent_id` instead of a\n * locale-bound row id.\n *\n * Before this, a term's `parent_id` pointed at one specific parent *row* (one\n * locale). A child translated in another locale could end up parented to a row\n * in a different locale, silently flattening that locale's tree (#1347). Every\n * other taxonomy i18n relationship already keys off `translation_group`\n * (`content_taxonomies.taxonomy_id`, `_emdash_menu_items.reference_id`), so this\n * aligns parentage with that model: a child links to the parent *concept* and\n * stays nested in whichever locale that parent has been translated into.\n *\n * Backfill rewrites every existing `parent_id` from the referenced parent row's\n * id to that parent's `translation_group`. A `translation_group` normally equals\n * its anchor row's id, so the self-FK on `parent_id` stays valid. We only\n * rewrite when that anchor row still exists; if a parent's anchor was deleted\n * but a sibling translation survives, the existing locale-bound id is left as-is\n * rather than rewritten to a dangling FK value. Such a child then renders as a\n * root rather than nested — an accepted degradation for an already-inconsistent\n * dataset (its `translation_group` already points at a deleted row, which breaks\n * `content_taxonomies` joins too). New deletes can't recreate this state: a\n * parent with children in any locale is undeletable. The correlated subquery is\n * a no-op for rows that already hold a group (an anchor row's id resolves to\n * itself), so the migration is safe to re-run.\n *\n * Dialect-independent: the correlated-subquery `UPDATE` runs on SQLite (incl.\n * D1) and Postgres alike.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tUPDATE taxonomies\n\t\tSET parent_id = (\n\t\t\tSELECT p.translation_group FROM taxonomies p WHERE p.id = taxonomies.parent_id\n\t\t)\n\t\tWHERE parent_id IS NOT NULL\n\t\t\tAND EXISTS (\n\t\t\t\tSELECT 1 FROM taxonomies p\n\t\t\t\tWHERE p.id = taxonomies.parent_id\n\t\t\t\t\tAND p.translation_group IS NOT NULL\n\t\t\t\t\t-- Only rewrite to a translation_group that is itself a live row\n\t\t\t\t\t-- id, so the self-FK on parent_id can never dangle.\n\t\t\t\t\tAND EXISTS (SELECT 1 FROM taxonomies a WHERE a.id = p.translation_group)\n\t\t\t)\n\t`.execute(db);\n}\n\n/**\n * Map each `parent_id` group back to the row id of the parent in the same\n * locale (the pre-migration shape). Rows with no same-locale parent are left as\n * they are rather than nulled, so a rollback never silently detaches a subtree.\n */\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait sql`\n\t\tUPDATE taxonomies\n\t\tSET parent_id = COALESCE(\n\t\t\t(\n\t\t\t\tSELECT c.id FROM taxonomies c\n\t\t\t\tWHERE c.translation_group = taxonomies.parent_id\n\t\t\t\t\tAND c.locale = taxonomies.locale\n\t\t\t),\n\t\t\tparent_id\n\t\t)\n\t\tWHERE parent_id IS NOT NULL\n\t`.execute(db);\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\n/**\n * Internal media usage projection tables.\n *\n * This migration is DDL-only by design: no backfill, no runtime media/indexing\n * imports, and no content-table scans. Production rows are introduced by later\n * phases once the central snapshot/indexer path is reviewed.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_sources\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"source_key\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"source_type\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"collection_slug\", \"text\")\n\t\t.addColumn(\"content_id\", \"text\")\n\t\t.addColumn(\"source_variant\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"locale\", \"text\")\n\t\t.addColumn(\"translation_group\", \"text\")\n\t\t.addColumn(\"content_slug\", \"text\")\n\t\t.addColumn(\"content_title\", \"text\")\n\t\t.addColumn(\"content_status\", \"text\")\n\t\t.addColumn(\"content_scheduled_at\", \"text\")\n\t\t.addColumn(\"content_deleted_at\", \"text\")\n\t\t.addColumn(\"revision_id\", \"text\")\n\t\t.addColumn(\"current_generation\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"schema_version\", \"integer\", (c) => c.notNull().defaultTo(1))\n\t\t.addColumn(\"indexed_at\", \"text\", (c) => c.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_content\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"source_type\", \"collection_slug\", \"content_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_variant\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"source_type\", \"source_variant\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_locale\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"collection_slug\", \"locale\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_deleted\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.column(\"content_deleted_at\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_translation_group\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"collection_slug\", \"translation_group\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"source_key\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"generation\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"field_slug\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"field_path\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"occurrence_index\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"reference_type\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"media_id\", \"text\")\n\t\t.addColumn(\"provider\", \"text\", (c) => c.notNull().defaultTo(\"local\"))\n\t\t.addColumn(\"provider_asset_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"media_kind\", \"text\")\n\t\t.addColumn(\"mime_type\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_unique_occurrence\")\n\t\t.ifNotExists()\n\t\t.unique()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"source_key\", \"generation\", \"field_path\", \"occurrence_index\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_media_id\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.column(\"media_id\")\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_provider_asset\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"provider\", \"provider_asset_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_source_generation\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"source_key\", \"generation\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_media_usage\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_sources\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Restore `idx_taxonomies_parent` on `taxonomies(parent_id)` (#1665).\n *\n * Migration 015 created this index, but 036's SQLite table rebuild\n * (`taxonomies_new` → drop → rename) dropped every index attached to the old\n * table and only recreated `name`/`locale`/`translation_group`. The parent\n * index — which backs hierarchical (parent/child) lookups — was silently lost\n * on any install migrated through 036. The Postgres path in 036 alters the\n * table in place and keeps its indexes, so it is unaffected; `ifNotExists`\n * makes this a no-op there.\n *\n * Forward-only: 036 has already shipped, so existing installs only recover the\n * index here. Fresh installs also get it in 036's rebuild for parity with the\n * other rebuilt tables, making this a no-op for them.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_parent\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.column(\"parent_id\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_taxonomies_parent\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Restore `idx_content_taxonomies_term` on `content_taxonomies(taxonomy_id)` (#1701).\n *\n * Migration 015 created this index. 036's SQLite/D1 table rebuild recreated it,\n * but the recreate was gated behind an FK-presence early-return: if a first run\n * committed the rebuild (stripping the FK and dropping the old index) and then\n * failed before the recreate, the retry saw zero FKs, skipped the whole body,\n * and never restored the index — while 036 was still recorded as applied. The\n * result was an install missing only this one index, with no forward migration\n * to recover it (the sibling `idx_taxonomies_parent` case was fixed by 047).\n *\n * 036 has since been fixed to recreate the index unconditionally, so fresh\n * installs are fine. This recovers the index on installs that hit the trap\n * before that fix. The Postgres path in 036 alters in place and keeps its\n * indexes, so it is unaffected; `ifNotExists` makes this a no-op there.\n *\n * Forward-only.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(\"idx_content_taxonomies_term\")\n\t\t.ifNotExists()\n\t\t.on(\"content_taxonomies\")\n\t\t.column(\"taxonomy_id\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_content_taxonomies_term\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\n/**\n * Add composite `idx_taxonomies_name_locale` on `taxonomies(name, locale)` (#1723).\n *\n * `TaxonomyRepository.findByName` filters `WHERE name = ? AND locale = ?`, but\n * the only indexes were the single-column `idx_taxonomies_name(name)` and\n * `idx_taxonomies_locale(locale)`. On SQLite/D1 with no `sqlite_stat1` the\n * planner picks `idx_taxonomies_locale` and reads *every* term in the locale,\n * filtering `name` in memory — once per facet rendered. On a site where one\n * taxonomy dominates a locale, each small facet still walks the whole locale.\n *\n * The composite resolves both equalities, so the planner searches only the one\n * taxonomy's terms. Its leftmost prefix (`name`) also serves every name-only\n * lookup, so it supersedes `idx_taxonomies_name`, which we drop. The\n * single-column `idx_taxonomies_locale` stays for locale-only lookups.\n *\n * Strictly additive: no query changes, and the dropped index is fully covered\n * by the new composite's prefix. Create-before-drop keeps name lookups indexed\n * at every point. Both statements are idempotent so a partial apply can retry.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_name_locale\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.columns([\"name\", \"locale\"])\n\t\t.execute();\n\n\tawait db.schema.dropIndex(\"idx_taxonomies_name\").ifExists().execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(\"idx_taxonomies_name\")\n\t\t.ifNotExists()\n\t\t.on(\"taxonomies\")\n\t\t.column(\"name\")\n\t\t.execute();\n\n\tawait db.schema.dropIndex(\"idx_taxonomies_name_locale\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists, currentTimestamp } from \"../dialect-helpers.js\";\n\nconst SOURCE_TABLE = \"_emdash_media_usage_sources\";\nconst DUPLICATE_COLUMN_RE = /(?:duplicate column|column .* already exists|already exists.*column)/i;\n\n/**\n * Media usage index metadata.\n *\n * DDL-only by design: adds freshness/completeness metadata and scope status\n * tracking for later reference-index reconciliation. No content scans, no\n * runtime imports, and no backfill.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait addSourceMetadataColumns(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_index_status\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"adapter_id\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"scope_type\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"scope_key\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"status\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"schema_version\", \"integer\", (c) => c.notNull().defaultTo(1))\n\t\t.addColumn(\"started_at\", \"text\")\n\t\t.addColumn(\"completed_at\", \"text\")\n\t\t.addColumn(\"cursor\", \"text\")\n\t\t.addColumn(\"indexed_source_count\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"failed_source_count\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addPrimaryKeyConstraint(\"_emdash_media_usage_index_status_pk\", [\n\t\t\t\"adapter_id\",\n\t\t\t\"scope_type\",\n\t\t\t\"scope_key\",\n\t\t])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_completeness\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"source_type\", \"collection_slug\", \"source_completeness\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_fingerprint\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.column(\"source_fingerprint\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_index_status_status\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_index_status\")\n\t\t.columns([\"adapter_id\", \"status\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_index_status_status\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_sources_fingerprint\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_sources_completeness\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_index_status\").ifExists().execute();\n\n\tawait dropSourceMetadataColumns(db);\n}\n\nasync function addSourceMetadataColumns(db: Kysely<unknown>): Promise<void> {\n\tawait addColumnIfMissing(db, \"source_updated_at\", () =>\n\t\tdb.schema.alterTable(SOURCE_TABLE).addColumn(\"source_updated_at\", \"text\").execute(),\n\t);\n\tawait addColumnIfMissing(db, \"source_version\", () =>\n\t\tdb.schema.alterTable(SOURCE_TABLE).addColumn(\"source_version\", \"integer\").execute(),\n\t);\n\tawait addColumnIfMissing(db, \"source_fingerprint\", () =>\n\t\tdb.schema.alterTable(SOURCE_TABLE).addColumn(\"source_fingerprint\", \"text\").execute(),\n\t);\n\tawait addColumnIfMissing(db, \"source_completeness\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(SOURCE_TABLE)\n\t\t\t.addColumn(\"source_completeness\", \"text\", (c) => c.notNull().defaultTo(\"unknown\"))\n\t\t\t.execute(),\n\t);\n\tawait addColumnIfMissing(db, \"last_attempted_at\", () =>\n\t\tdb.schema.alterTable(SOURCE_TABLE).addColumn(\"last_attempted_at\", \"text\").execute(),\n\t);\n\tawait addColumnIfMissing(db, \"last_error_code\", () =>\n\t\tdb.schema.alterTable(SOURCE_TABLE).addColumn(\"last_error_code\", \"text\").execute(),\n\t);\n}\n\nasync function addColumnIfMissing(\n\tdb: Kysely<unknown>,\n\tcolumnName: string,\n\taddColumn: () => Promise<void>,\n): Promise<void> {\n\tif (await columnExists(db, SOURCE_TABLE, columnName)) return;\n\n\ttry {\n\t\tawait addColumn();\n\t} catch (error) {\n\t\tif (DUPLICATE_COLUMN_RE.test(deepErrorMessage(error))) {\n\t\t\tif (await columnExists(db, SOURCE_TABLE, columnName)) return;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction deepErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst own = error.message ?? \"\";\n\t\tif (error.cause) {\n\t\t\tconst causeMessage = deepErrorMessage(error.cause);\n\t\t\treturn own ? `${own}: ${causeMessage}` : causeMessage;\n\t\t}\n\t\treturn own;\n\t}\n\tif (typeof error === \"string\") return error;\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n\nasync function dropSourceMetadataColumns(db: Kysely<unknown>): Promise<void> {\n\tfor (const columnName of [\n\t\t\"last_error_code\",\n\t\t\"last_attempted_at\",\n\t\t\"source_completeness\",\n\t\t\"source_fingerprint\",\n\t\t\"source_version\",\n\t\t\"source_updated_at\",\n\t] as const) {\n\t\tif (await columnExists(db, SOURCE_TABLE, columnName)) {\n\t\t\tawait db.schema.alterTable(SOURCE_TABLE).dropColumn(columnName).execute();\n\t\t}\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { columnExists, listTablesLike } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * Denormalize the filter + sort columns from `ec_*` onto `content_taxonomies`\n * and mirror `ec_*`'s composite sort indexes onto the pivot (#1834).\n *\n * A taxonomy-filtered listing used to apply the term filter as a correlated\n * `EXISTS` on `SELECT * FROM ec_<collection> … ORDER BY … LIMIT ?`. The pivot\n * carried only `(collection, entry_id, taxonomy_id)`, so the filter\n * (`deleted_at`, `status`, `locale`) and the sort (`published_at`/`created_at`)\n * could only be evaluated on the `ec_*` row. On stats-blind SQLite/D1 a\n * selective term never fills the `LIMIT`, so the query walked the whole\n * collection (~75k D1 rows read for a one-row page).\n *\n * Copying those columns onto the pivot and indexing them keyed by\n * `(taxonomy_id, collection, …)` lets the loader seek the term and walk a\n * sort-ordered pivot index, short-circuiting on `LIMIT`, then touch `ec_*` only\n * by primary key to hydrate the page.\n *\n * The columns are advisory (D1 has no transactions; the write-path re-stamp is\n * non-atomic), so the read path re-checks the real predicates on the joined\n * `ec_*` row — see loader.ts. `updated_at` is deliberately not denormalized: it\n * moves on every edit and is seldom a public sort, so its write cost outweighs\n * its read value; `updated_at`-sorted taxonomy listings temp-sort instead.\n *\n * Order matters: add the columns, backfill, THEN build the indexes so each\n * index is built once over populated data rather than maintained through the\n * backfill `UPDATE`.\n *\n * Forward-only.\n */\n\nconst DENORM_COLUMNS = [\n\t\"status\",\n\t\"scheduled_at\",\n\t\"deleted_at\",\n\t\"locale\",\n\t\"published_at\",\n\t\"created_at\",\n] as const;\n\n// `entry_id DESC` (not ASC) matters: the listing orders `<sort> DESC, entry_id\n// DESC` (the common case), and a DESC tiebreaker lets SQLite satisfy the whole\n// ORDER BY from the index — no temp B-tree, clean early-`LIMIT`. An ASC\n// tiebreaker forces `USE TEMP B-TREE FOR LAST TERM OF ORDER BY`, which buffers\n// a whole equal-`sortval` block (e.g. a bulk import sharing one timestamp)\n// before emitting. `DESC` also serves the rarer ASC listing via a backward\n// index scan. Mirrors `ec_*`'s `(deleted_at, [locale,] <sort> DESC, id DESC)`.\nconst INDEXES: { name: string; columns: string }[] = [\n\t{\n\t\tname: \"idx_content_taxonomies_pub\",\n\t\tcolumns: \"taxonomy_id, collection, deleted_at, published_at DESC, entry_id DESC\",\n\t},\n\t{\n\t\tname: \"idx_content_taxonomies_crt\",\n\t\tcolumns: \"taxonomy_id, collection, deleted_at, created_at DESC, entry_id DESC\",\n\t},\n\t{\n\t\tname: \"idx_content_taxonomies_loc_pub\",\n\t\tcolumns: \"taxonomy_id, collection, deleted_at, locale, published_at DESC, entry_id DESC\",\n\t},\n\t{\n\t\tname: \"idx_content_taxonomies_loc_crt\",\n\t\tcolumns: \"taxonomy_id, collection, deleted_at, locale, created_at DESC, entry_id DESC\",\n\t},\n];\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// 1. Add the six denormalized columns (all nullable, no default). Guarded so\n\t// a partial apply — or a re-run after a mid-migration failure — can retry\n\t// (`ALTER TABLE ADD COLUMN` is not itself idempotent on either dialect).\n\tfor (const column of DENORM_COLUMNS) {\n\t\tif (await columnExists(db, \"content_taxonomies\", column)) continue;\n\t\tawait sql`\n\t\t\tALTER TABLE content_taxonomies ADD COLUMN ${sql.ref(column)} TEXT\n\t\t`.execute(db);\n\t}\n\n\t// 2. Backfill from each content table by primary key. Drive from the actual\n\t// `ec_*` tables (not `_emdash_collections`) so collections whose table was\n\t// dropped are skipped naturally; the pivot's `collection` value is the\n\t// slug, i.e. the table name without its `ec_` prefix.\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tfor (const tableName of tableNames) {\n\t\tvalidateIdentifier(tableName, \"content table name\");\n\t\tconst slug = tableName.slice(\"ec_\".length);\n\t\tawait sql`\n\t\t\tUPDATE content_taxonomies\n\t\t\tSET (status, scheduled_at, deleted_at, locale, published_at, created_at) = (\n\t\t\t\tSELECT status, scheduled_at, deleted_at, locale, published_at, created_at\n\t\t\t\tFROM ${sql.ref(tableName)}\n\t\t\t\tWHERE ${sql.ref(tableName)}.id = content_taxonomies.entry_id\n\t\t\t)\n\t\t\tWHERE collection = ${slug}\n\t\t`.execute(db);\n\t}\n\n\t// 3. Build the composite sort indexes over the now-populated columns.\n\tfor (const index of INDEXES) {\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(index.name)}\n\t\t\tON content_taxonomies (${sql.raw(index.columns)})\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tfor (const index of INDEXES) {\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(index.name)}`.execute(db);\n\t}\n\tfor (const column of DENORM_COLUMNS) {\n\t\tawait sql`\n\t\t\tALTER TABLE content_taxonomies DROP COLUMN ${sql.ref(column)}\n\t\t`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nconst OLD_INDEX = \"idx__emdash_media_usage_media_id\";\nconst READ_INDEX = \"idx__emdash_media_usage_media_source_generation\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\t// D1 DDL is non-transactional: create the replacement before dropping the\n\t// old index so an interrupted migration always leaves a media-leading index.\n\tawait db.schema\n\t\t.createIndex(READ_INDEX)\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"media_id\", \"source_key\", \"generation\"])\n\t\t.execute();\n\tawait db.schema.dropIndex(OLD_INDEX).ifExists().execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(OLD_INDEX)\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.column(\"media_id\")\n\t\t.execute();\n\tawait db.schema.dropIndex(READ_INDEX).ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/** Persist explicit per-plugin MCP enablement and the declaration consented to by an admin. */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_plugin_state\", \"mcp_tools_enabled\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_plugin_state\")\n\t\t\t.addColumn(\"mcp_tools_enabled\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t\t.execute();\n\t}\n\tif (!(await columnExists(db, \"_plugin_state\", \"mcp_tools_consent\"))) {\n\t\tawait db.schema.alterTable(\"_plugin_state\").addColumn(\"mcp_tools_consent\", \"text\").execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.alterTable(\"_plugin_state\").dropColumn(\"mcp_tools_consent\").execute();\n\tawait db.schema.alterTable(\"_plugin_state\").dropColumn(\"mcp_tools_enabled\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_upload_attempts\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"storage_key\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"media_id\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(\"active\"))\n\t\t.addColumn(\"created_at\", \"text\", (col) => col.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addColumn(\"updated_at\", \"text\", (col) => col.notNull().defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_media_upload_attempts_media_id\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_upload_attempts\")\n\t\t.column(\"media_id\")\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_media_upload_attempts_status_created_at\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_upload_attempts\")\n\t\t.columns([\"status\", \"created_at\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_media_storage_key\")\n\t\t.ifNotExists()\n\t\t.on(\"media\")\n\t\t.column(\"storage_key\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_media_storage_key\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_upload_attempts\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: replace the single-column content `translation_group` index with\n * one index per translation-group read shape.\n *\n * There are two shapes. Translation-group reads filter `deleted_at IS NULL`\n * with `translation_group = ?` / `IN (...)` and order by locale; menu and\n * reference resolution looks a group up by `translation_group` (+ `locale`)\n * alone, with no `deleted_at` term.\n *\n * Neither shape can borrow the other's index. Seeking migration 041's\n * `(deleted_at, locale, ...)` composites on `deleted_at` alone already returns\n * rows in locale order, so a stats-blind planner prefers them over a\n * single-column `translation_group` index and reads every non-deleted row in\n * the table; the batched variant is worse still, because the `IN (...)` list\n * multiplies the planner's row estimate for a `translation_group`-leading index\n * and it falls back to a `deleted_at` composite from a handful of groups\n * onward. Going the other way, an index leading with `deleted_at` cannot seek a\n * lookup that never constrains that column. D1 never has `sqlite_stat1`, so the\n * index shape is the only lever and each shape needs a prefix matching it term\n * for term.\n *\n * Forward-only and idempotent (`IF NOT EXISTS`).\n *\n * Index names use short `tg_locale` / `del_tg_locale` suffixes rather than\n * spelling out `translation_group`: Postgres truncates identifiers to 63 bytes,\n * and the longer forms truncate to the same value for long collection slugs.\n * Keep these identical to the names in `schema/registry.ts`.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\t// D1 DDL is non-transactional: create the replacements before dropping the\n\t\t// old index so an interrupted migration always leaves a\n\t\t// translation_group-leading index in place.\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${tableName}_tg_locale`)}\n\t\t\tON ${sql.ref(tableName)} (translation_group, locale)\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${tableName}_del_tg_locale`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, translation_group, locale)\n\t\t`.execute(db);\n\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_translation_group`)}`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${tableName}_translation_group`)}\n\t\t\tON ${sql.ref(tableName)} (translation_group)\n\t\t`.execute(db);\n\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_del_tg_locale`)}`.execute(db);\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_tg_locale`)}`.execute(db);\n\t}\n}\n","import { sql, type Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/**\n * Add `taxonomies.sort_order` and mint a position for every existing term.\n *\n * A position belongs to a `translation_group`, not a row: every row of a group\n * carries the same value. Groups are numbered by `(label, id)` — the order term\n * listings used before this migration — taking the label from the group's lowest\n * row id. That locale's rendered order is unchanged; every other locale is\n * re-sorted to match it, since only one locale's collation can win.\n *\n * Sibling groups are keyed on the raw `parent_id` column, which holds the\n * parent's translation_group, so a group whose rows disagree about their parent\n * is reconciled before numbering — otherwise it lands in whichever sibling group\n * one arbitrary row happens to name.\n *\n * Only the `ALTER` is guarded; the passes below run unconditionally so a run that\n * dies partway can be retried. Guarding the whole migration strands a partial\n * numbering, because the retry early-returns on the column it added.\n */\n\n/**\n * Translation groups per `UPDATE`. Each costs three bound parameters — a CASE\n * `WHEN`/`THEN` pair plus one slot in the `IN` list — which keeps a statement\n * inside D1's 100-parameter ceiling. Writing one group per statement instead\n * spends a subrequest per term, and a large taxonomy exhausts the 1,000 a\n * Worker gets on the free plan before the migration finishes.\n */\nconst GROUPS_PER_UPDATE = 32;\n\ninterface TermRow {\n\tid: string;\n\tname: string;\n\tlabel: string | null;\n\tparent_id: string | null;\n\ttranslation_group: string;\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst fresh = !(await columnExists(db, \"taxonomies\", \"sort_order\"));\n\tif (fresh) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"taxonomies\")\n\t\t\t.addColumn(\"sort_order\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t\t.execute();\n\t}\n\n\t// Migration 036 seeded `translation_group = id` on every row it rebuilt, and\n\t// the repository has set it on every insert since, so this normally matches\n\t// nothing. It runs anyway because everything below keys sibling groups on the\n\t// column directly: a row that slipped through with a null would be numbered\n\t// into no group at all, and would already be invisible to translation lookups\n\t// and to `content_taxonomies`, which joins on the same value.\n\tawait sql`UPDATE taxonomies SET translation_group = id WHERE translation_group IS NULL`.execute(\n\t\tdb,\n\t);\n\n\tconst { rows } = await sql<TermRow>`\n\t\tSELECT id, name, label, parent_id, translation_group FROM taxonomies\n\t`.execute(db);\n\n\tawait repairParents(db, rows);\n\tawait mintPositions(db, rows, fresh);\n}\n\n/**\n * Give every row of a translation_group the same `parent_id`, mutating `rows` so\n * the numbering below sees the reconciled tree.\n *\n * `parent_id` holds the parent's translation_group, so it is locale-agnostic and\n * a group's rows should all agree. Reparenting used to write a single row, which\n * left a term nested in the locale it was moved in and a root everywhere else.\n * A non-null parent wins: it is the move somebody made, and the null is the row\n * that missed it.\n *\n * The winner is copied from a sibling row, so it already satisfies the self-FK\n * on `parent_id` and can't be rewritten into a dangling reference.\n */\nasync function repairParents(db: Kysely<unknown>, rows: TermRow[]): Promise<void> {\n\tconst byGroup = new Map<string, TermRow[]>();\n\tfor (const row of rows) {\n\t\tconst group = row.translation_group;\n\t\tlet members = byGroup.get(group);\n\t\tif (!members) byGroup.set(group, (members = []));\n\t\tmembers.push(row);\n\t}\n\n\tconst winners = new Map<string, string>();\n\tfor (const [group, members] of byGroup) {\n\t\tif (new Set(members.map((member) => member.parent_id)).size < 2) continue;\n\n\t\tconst parented = members.filter((member) => member.parent_id !== null);\n\t\t// The anchor row decides when it names a parent, else the lowest row id\n\t\t// that does, so the choice is the same however the rows come back.\n\t\tconst anchor = parented.find((member) => member.id === group);\n\t\tconst decider = anchor ?? parented.toSorted((a, b) => a.id.localeCompare(b.id))[0];\n\t\tconst winner = decider?.parent_id;\n\t\tif (winner === undefined || winner === null) continue;\n\n\t\twinners.set(group, winner);\n\t\tfor (const member of members) member.parent_id = winner;\n\t}\n\n\tawait applyByGroup(db, \"parent_id\", winners);\n}\n\n/**\n * Number each sibling group by `(label, id)`.\n *\n * When the column was just added every row already reads 0, so those positions\n * are left to the default. On a retry the column is already there and may hold\n * numbers from the run that failed, so every position is written explicitly.\n */\nasync function mintPositions(\n\tdb: Kysely<unknown>,\n\trows: readonly TermRow[],\n\tfresh: boolean,\n): Promise<void> {\n\t// One entry per translation_group: a group holds a single position, and its\n\t// rows can disagree on label across locales, so the lowest row id decides for\n\t// the whole group. Taxonomy names are `[a-z][a-z0-9_]*` and parents are\n\t// ULIDs, so \"/\" can't appear in either half of the sibling key.\n\tconst groups = new Map<string, { sibling: string; label: string; id: string }>();\n\tfor (const row of rows) {\n\t\tconst group = row.translation_group;\n\t\tconst chosen = groups.get(group);\n\t\tif (chosen && chosen.id <= row.id) continue;\n\t\tgroups.set(group, {\n\t\t\tsibling: row.name + \"/\" + (row.parent_id ?? \"\"),\n\t\t\tlabel: row.label ?? \"\",\n\t\t\tid: row.id,\n\t\t});\n\t}\n\n\tconst siblings = new Map<string, { group: string; label: string; id: string }[]>();\n\tfor (const [group, { sibling, label, id }] of groups) {\n\t\tlet members = siblings.get(sibling);\n\t\tif (!members) siblings.set(sibling, (members = []));\n\t\tmembers.push({ group, label, id });\n\t}\n\n\tconst positions = new Map<string, number>();\n\tfor (const members of siblings.values()) {\n\t\tmembers.sort((a, b) => a.label.localeCompare(b.label) || a.id.localeCompare(b.id));\n\t\tfor (const [position, member] of members.entries()) {\n\t\t\tif (position === 0 && fresh) continue;\n\t\t\tpositions.set(member.group, position);\n\t\t}\n\t}\n\n\tawait applyByGroup(db, \"sort_order\", positions);\n}\n\n/**\n * Set one column per translation_group, chunked to stay inside the parameter\n * ceiling.\n */\nasync function applyByGroup(\n\tdb: Kysely<unknown>,\n\tcolumn: \"parent_id\" | \"sort_order\",\n\tvalues: ReadonlyMap<string, string | number>,\n): Promise<void> {\n\tconst entries = [...values];\n\t// The CAST types the bound value. Postgres resolves a CASE whose THEN arms are\n\t// all untyped parameters to text, then refuses to assign text to an integer\n\t// column.\n\tconst valueType = column === \"sort_order\" ? sql`INTEGER` : sql`TEXT`;\n\tfor (let index = 0; index < entries.length; index += GROUPS_PER_UPDATE) {\n\t\tconst chunk = entries.slice(index, index + GROUPS_PER_UPDATE);\n\t\tconst arms = sql.join(\n\t\t\tchunk.map(([group, value]) => sql`WHEN ${group} THEN CAST(${value} AS ${valueType})`),\n\t\t\tsql` `,\n\t\t);\n\t\tconst keys = sql.join(chunk.map(([group]) => sql`${group}`));\n\t\tawait sql`\n\t\t\tUPDATE taxonomies\n\t\t\tSET ${sql.ref(column)} = CASE translation_group ${arms} END\n\t\t\tWHERE translation_group IN (${keys})\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"taxonomies\", \"sort_order\")) {\n\t\tawait db.schema.alterTable(\"taxonomies\").dropColumn(\"sort_order\").execute();\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/**\n * Migration: hide a collection from the admin sidebar.\n *\n * Adds `hidden` to `_emdash_collections`. A hidden collection stays fully\n * functional (REST API, MCP, plugin hooks, direct `/content/:collection`\n * URLs) — only its auto-generated sidebar entry is omitted, so plugins that\n * own a collection end to end can steer editors to their own admin UI.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_collections\", \"hidden\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_collections\")\n\t\t\t.addColumn(\"hidden\", \"integer\", (col) => col.notNull().defaultTo(0))\n\t\t\t.execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.alterTable(\"_emdash_collections\").dropColumn(\"hidden\").execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/**\n * Migration: explicit collection order in the admin sidebar.\n *\n * Adds `sort_order` to `_emdash_collections`. A NULL `sort_order` means no\n * explicit position: those collections sort after the ordered ones, keeping\n * the alphabetical-by-slug order.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_collections\", \"sort_order\"))) {\n\t\tawait db.schema.alterTable(\"_emdash_collections\").addColumn(\"sort_order\", \"integer\").execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.alterTable(\"_emdash_collections\").dropColumn(\"sort_order\").execute();\n}\n","import { sql, type Kysely } from \"kysely\";\n\nconst REVISION_KEEP_COUNT = 50;\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_revision_prune_queue\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"collection\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"entry_id\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"revision_id\", \"text\", (column) => column.notNull())\n\t\t.addPrimaryKeyConstraint(\"revision_prune_queue_pk\", [\"collection\", \"entry_id\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx_revision_prune_queue_revision_id\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_revision_prune_queue\")\n\t\t.column(\"revision_id\")\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_revision_prune_queue (collection, entry_id, revision_id)\n\t\tSELECT collection, entry_id, MAX(id)\n\t\tFROM revisions\n\t\tWHERE true\n\t\tGROUP BY collection, entry_id\n\t\tHAVING COUNT(*) > ${REVISION_KEEP_COUNT}\n\t\tON CONFLICT (collection, entry_id)\n\t\tDO UPDATE SET revision_id = excluded.revision_id\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropTable(\"_emdash_revision_prune_queue\").ifExists().execute();\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/** Persist collection-level admin presentation options. */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_collections\", \"admin_config\"))) {\n\t\tawait db.schema.alterTable(\"_emdash_collections\").addColumn(\"admin_config\", \"text\").execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"_emdash_collections\", \"admin_config\")) {\n\t\tawait db.schema.alterTable(\"_emdash_collections\").dropColumn(\"admin_config\").execute();\n\t}\n}\n","import { sql, type Kysely } from \"kysely\";\n\nimport { currentTimestamp } from \"../dialect-helpers.js\";\n\nconst CLEANUP_TASK_KEY = \"projection_gc\";\nconst INITIAL_ELIGIBLE_AT = \"1970-01-01T00:00:00.000Z\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_cleanup_scan\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"created_at\", \"id\", \"source_key\", \"generation\"])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_cleanup\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"task_key\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"lease_token\", \"text\")\n\t\t.addColumn(\"lease_expires_at\", \"text\")\n\t\t.addColumn(\"next_eligible_at\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"cursor_created_at\", \"text\")\n\t\t.addColumn(\"cursor_id\", \"text\")\n\t\t.addColumn(\"scan_before_at\", \"text\")\n\t\t.addColumn(\"consecutive_failures\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_started_at\", \"text\")\n\t\t.addColumn(\"last_completed_at\", \"text\")\n\t\t.addColumn(\"last_candidate_count\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_deleted_orphans\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_deleted_stale\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_deleted_abandoned\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_deleted_write_leases\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_backlog_lower_bound\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_scan_has_more\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_duration_ms\", \"integer\", (c) => c.notNull().defaultTo(0))\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.notNull().defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_generation_writes\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"source_key\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"generation\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"lease_token\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"expires_at\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"created_at\", \"text\", (c) => c.notNull().defaultTo(currentTimestamp(db)))\n\t\t.addUniqueConstraint(\"_emdash_media_usage_generation_writes_source_generation\", [\n\t\t\t\"source_key\",\n\t\t\t\"generation\",\n\t\t])\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_generation_writes_expiry\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_generation_writes\")\n\t\t.columns([\"expires_at\", \"lease_token\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_media_usage_cleanup (task_key, next_eligible_at)\n\t\tVALUES (${CLEANUP_TASK_KEY}, ${INITIAL_ELIGIBLE_AT})\n\t\tON CONFLICT (task_key) DO NOTHING\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.dropIndex(\"idx__emdash_media_usage_generation_writes_expiry\")\n\t\t.ifExists()\n\t\t.execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_generation_writes\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_cleanup\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_cleanup_scan\").ifExists().execute();\n}\n","import { sql, type Kysely } from \"kysely\";\n\nimport { columnExists, currentTimestamp, isPostgres } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_media_usage\", \"cleanup_lease_token\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_media_usage\")\n\t\t\t.addColumn(\"cleanup_lease_token\", \"text\")\n\t\t\t.execute();\n\t}\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_cleanup_fence\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"task_key\", \"text\", (c) => c.primaryKey())\n\t\t.addColumn(\"generation_floor\", \"text\", (c) => c.notNull())\n\t\t.addColumn(\"updated_at\", \"text\", (c) => c.notNull().defaultTo(currentTimestamp(db)))\n\t\t.execute();\n\n\tif (isPostgres(db)) {\n\t\tawait sql\n\t\t\t.raw(\"DROP TRIGGER IF EXISTS emdash_media_usage_record_cleanup_fence ON _emdash_media_usage\")\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_update ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_insert ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_update ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_insert ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_delete ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE OR REPLACE FUNCTION emdash_media_usage_lock_cleanup()\n\t\t\tRETURNS trigger\n\t\t\tLANGUAGE plpgsql\n\t\t\tAS $$\n\t\t\tBEGIN\n\t\t\t\tPERFORM 1\n\t\t\t\tFROM _emdash_media_usage_cleanup AS cleanup\n\t\t\t\tWHERE cleanup.task_key = 'projection_gc'\n\t\t\t\tFOR SHARE;\n\t\t\t\tRETURN NULL;\n\t\t\tEND;\n\t\t\t$$\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE OR REPLACE FUNCTION emdash_media_usage_fence_source_generation()\n\t\t\tRETURNS trigger\n\t\t\tLANGUAGE plpgsql\n\t\t\tAS $$\n\t\t\tBEGIN\n\t\t\t\tIF EXISTS (\n\t\t\t\t\tSELECT 1\n\t\t\t\t\tFROM _emdash_media_usage_cleanup_fence AS fence\n\t\t\t\t\tWHERE fence.task_key = 'projection_gc'\n\t\t\t\t\t\tAND NEW.current_generation <= fence.generation_floor\n\t\t\t\t) AND NOT EXISTS (\n\t\t\t\t\tSELECT 1\n\t\t\t\t\tFROM _emdash_media_usage_generation_writes AS writer\n\t\t\t\t\tWHERE writer.source_key = NEW.source_key\n\t\t\t\t\t\tAND writer.generation = NEW.current_generation\n\t\t\t\t\t\tAND writer.expires_at::timestamptz > clock_timestamp()\n\t\t\t\t) THEN\n\t\t\t\t\tRETURN NULL;\n\t\t\t\tEND IF;\n\t\t\t\tRETURN NEW;\n\t\t\tEND;\n\t\t\t$$\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_lock_cleanup_insert\n\t\t\tBEFORE INSERT ON _emdash_media_usage_sources\n\t\t\tFOR EACH STATEMENT\n\t\t\tEXECUTE FUNCTION emdash_media_usage_lock_cleanup()\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_lock_cleanup_update\n\t\t\tBEFORE UPDATE OF current_generation ON _emdash_media_usage_sources\n\t\t\tFOR EACH STATEMENT\n\t\t\tEXECUTE FUNCTION emdash_media_usage_lock_cleanup()\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_lock_cleanup_delete\n\t\t\tBEFORE DELETE ON _emdash_media_usage_sources\n\t\t\tFOR EACH STATEMENT\n\t\t\tEXECUTE FUNCTION emdash_media_usage_lock_cleanup()\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE OR REPLACE FUNCTION emdash_media_usage_record_cleanup_fence()\n\t\t\tRETURNS trigger\n\t\t\tLANGUAGE plpgsql\n\t\t\tAS $$\n\t\t\tBEGIN\n\t\t\t\tIF OLD.cleanup_lease_token IS NOT NULL AND EXISTS (\n\t\t\t\t\tSELECT 1\n\t\t\t\t\tFROM _emdash_media_usage_cleanup AS cleanup\n\t\t\t\t\tWHERE cleanup.task_key = 'projection_gc'\n\t\t\t\t\t\tAND cleanup.lease_token = OLD.cleanup_lease_token\n\t\t\t\t) THEN\n\t\t\t\t\tINSERT INTO _emdash_media_usage_cleanup_fence (\n\t\t\t\t\t\ttask_key,\n\t\t\t\t\t\tgeneration_floor,\n\t\t\t\t\t\tupdated_at\n\t\t\t\t\t)\n\t\t\t\t\tVALUES ('projection_gc', OLD.generation, CURRENT_TIMESTAMP::text)\n\t\t\t\t\tON CONFLICT (task_key) DO UPDATE SET\n\t\t\t\t\t\tgeneration_floor = CASE\n\t\t\t\t\t\t\tWHEN EXCLUDED.generation_floor > _emdash_media_usage_cleanup_fence.generation_floor\n\t\t\t\t\t\t\tTHEN EXCLUDED.generation_floor\n\t\t\t\t\t\t\tELSE _emdash_media_usage_cleanup_fence.generation_floor\n\t\t\t\t\t\tEND,\n\t\t\t\t\t\tupdated_at = EXCLUDED.updated_at;\n\t\t\t\tEND IF;\n\t\t\t\tRETURN OLD;\n\t\t\tEND;\n\t\t\t$$\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_fence_source_generation_insert\n\t\t\tBEFORE INSERT ON _emdash_media_usage_sources\n\t\t\tFOR EACH ROW\n\t\t\tEXECUTE FUNCTION emdash_media_usage_fence_source_generation()\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_fence_source_generation_update\n\t\t\tBEFORE UPDATE OF current_generation ON _emdash_media_usage_sources\n\t\t\tFOR EACH ROW\n\t\t\tEXECUTE FUNCTION emdash_media_usage_fence_source_generation()\n\t\t`)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER emdash_media_usage_record_cleanup_fence\n\t\t\tBEFORE DELETE ON _emdash_media_usage\n\t\t\tFOR EACH ROW\n\t\t\tWHEN (OLD.cleanup_lease_token IS NOT NULL)\n\t\t\tEXECUTE FUNCTION emdash_media_usage_record_cleanup_fence()\n\t\t`)\n\t\t\t.execute(db);\n\t\treturn;\n\t}\n\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS emdash_media_usage_fence_source_generation_insert\n\t\tBEFORE INSERT ON _emdash_media_usage_sources\n\t\tWHEN EXISTS (\n\t\t\tSELECT 1\n\t\t\tFROM _emdash_media_usage_cleanup_fence AS fence\n\t\t\tWHERE fence.task_key = 'projection_gc'\n\t\t\t\tAND NEW.current_generation <= fence.generation_floor\n\t\t) AND NOT EXISTS (\n\t\t\tSELECT 1\n\t\t\tFROM _emdash_media_usage_generation_writes AS writer\n\t\t\tWHERE writer.source_key = NEW.source_key\n\t\t\t\tAND writer.generation = NEW.current_generation\n\t\t\t\tAND writer.expires_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now')\n\t\t)\n\t\tBEGIN\n\t\t\tSELECT RAISE(IGNORE);\n\t\tEND\n\t`)\n\t\t.execute(db);\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS emdash_media_usage_fence_source_generation_update\n\t\tBEFORE UPDATE OF current_generation ON _emdash_media_usage_sources\n\t\tWHEN NEW.current_generation <> OLD.current_generation\n\t\t\tAND EXISTS (\n\t\t\t\tSELECT 1\n\t\t\t\tFROM _emdash_media_usage_cleanup_fence AS fence\n\t\t\t\tWHERE fence.task_key = 'projection_gc'\n\t\t\t\t\tAND NEW.current_generation <= fence.generation_floor\n\t\t\t) AND NOT EXISTS (\n\t\t\t\tSELECT 1\n\t\t\t\tFROM _emdash_media_usage_generation_writes AS writer\n\t\t\t\tWHERE writer.source_key = NEW.source_key\n\t\t\t\t\tAND writer.generation = NEW.current_generation\n\t\t\t\t\tAND writer.expires_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now')\n\t\t\t)\n\t\tBEGIN\n\t\t\tSELECT RAISE(IGNORE);\n\t\tEND\n\t`)\n\t\t.execute(db);\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS emdash_media_usage_record_cleanup_fence\n\t\tBEFORE DELETE ON _emdash_media_usage\n\t\tWHEN OLD.cleanup_lease_token IS NOT NULL AND EXISTS (\n\t\t\tSELECT 1\n\t\t\tFROM _emdash_media_usage_cleanup AS cleanup\n\t\t\tWHERE cleanup.task_key = 'projection_gc'\n\t\t\t\tAND cleanup.lease_token = OLD.cleanup_lease_token\n\t\t)\n\t\tBEGIN\n\t\t\tINSERT INTO _emdash_media_usage_cleanup_fence (\n\t\t\t\ttask_key,\n\t\t\t\tgeneration_floor,\n\t\t\t\tupdated_at\n\t\t\t)\n\t\t\tVALUES ('projection_gc', OLD.generation, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n\t\t\tON CONFLICT (task_key) DO UPDATE SET\n\t\t\t\tgeneration_floor = CASE\n\t\t\t\t\tWHEN excluded.generation_floor > _emdash_media_usage_cleanup_fence.generation_floor\n\t\t\t\t\tTHEN excluded.generation_floor\n\t\t\t\t\tELSE _emdash_media_usage_cleanup_fence.generation_floor\n\t\t\t\tEND,\n\t\t\t\tupdated_at = excluded.updated_at;\n\t\tEND\n\t`)\n\t\t.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (isPostgres(db)) {\n\t\tawait sql\n\t\t\t.raw(\"DROP TRIGGER IF EXISTS emdash_media_usage_record_cleanup_fence ON _emdash_media_usage\")\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_update ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_insert ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_update ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_insert ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\n\t\t\t\t\"DROP TRIGGER IF EXISTS emdash_media_usage_lock_cleanup_delete ON _emdash_media_usage_sources\",\n\t\t\t)\n\t\t\t.execute(db);\n\t\tawait sql.raw(\"DROP FUNCTION IF EXISTS emdash_media_usage_record_cleanup_fence()\").execute(db);\n\t\tawait sql\n\t\t\t.raw(\"DROP FUNCTION IF EXISTS emdash_media_usage_fence_source_generation()\")\n\t\t\t.execute(db);\n\t\tawait sql.raw(\"DROP FUNCTION IF EXISTS emdash_media_usage_lock_cleanup()\").execute(db);\n\t} else {\n\t\tawait sql.raw(\"DROP TRIGGER IF EXISTS emdash_media_usage_record_cleanup_fence\").execute(db);\n\t\tawait sql\n\t\t\t.raw(\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_update\")\n\t\t\t.execute(db);\n\t\tawait sql\n\t\t\t.raw(\"DROP TRIGGER IF EXISTS emdash_media_usage_fence_source_generation_insert\")\n\t\t\t.execute(db);\n\t}\n\tawait db.schema.dropTable(\"_emdash_media_usage_cleanup_fence\").ifExists().execute();\n\tif (await columnExists(db, \"_emdash_media_usage\", \"cleanup_lease_token\")) {\n\t\tawait db.schema.alterTable(\"_emdash_media_usage\").dropColumn(\"cleanup_lease_token\").execute();\n\t}\n}\n","import { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { columnExists, isPostgres, tableExists } from \"../dialect-helpers.js\";\n\nconst ACTIVATION_KEY = \"incremental_capture\";\nconst CONTENT_ADAPTER_ID = \"content-media\";\nconst COLLECTION_SCOPE = \"collection\";\nconst DUPLICATE_COLUMN_RE = /(?:duplicate column|column .* already exists|already exists.*column)/i;\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_activation\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"task_key\", \"text\", (column) => column.primaryKey())\n\t\t.addColumn(\"state\", \"text\", (column) => column.notNull().defaultTo(\"expanded\"))\n\t\t.addColumn(\"runtime_generation\", \"integer\", (column) => column.notNull().defaultTo(1))\n\t\t.addColumn(\"collection_cursor\", \"text\")\n\t\t.addColumn(\"drain_confirmed_at\", \"text\")\n\t\t.addColumn(\"lease_token\", \"text\")\n\t\t.addColumn(\"lease_expires_at\", \"text\")\n\t\t.addColumn(\"attempt_count\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t.addColumn(\"last_attempted_at\", \"text\")\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"activated_at\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.addColumn(\"updated_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.execute();\n\n\tawait sql`\n\t\tINSERT INTO _emdash_media_usage_activation (task_key, state)\n\t\tVALUES (${ACTIVATION_KEY}, 'expanded')\n\t\tON CONFLICT (task_key) DO NOTHING\n\t`.execute(db);\n\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_work\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"collection_id\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"collection_slug\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"content_id\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"change_epoch\", \"bigint\", (column) => column.notNull())\n\t\t.addColumn(\"work_version\", \"bigint\", (column) => column.notNull().defaultTo(1))\n\t\t.addColumn(\"state\", \"text\", (column) => column.notNull().defaultTo(\"pending\"))\n\t\t.addColumn(\"attempt_count\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t.addColumn(\"next_attempt_at\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"lease_token\", \"text\")\n\t\t.addColumn(\"lease_expires_at\", \"text\")\n\t\t.addColumn(\"last_attempted_at\", \"text\")\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.addColumn(\"updated_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.addPrimaryKeyConstraint(\"_emdash_media_usage_work_pk\", [\"collection_id\", \"content_id\"])\n\t\t.execute();\n\n\tawait addStatusColumns(db);\n\tawait addSourceColumns(db);\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_work_due\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_work\")\n\t\t.columns([\"state\", \"next_attempt_at\", \"updated_at\", \"collection_id\", \"content_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_work_lease\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_work\")\n\t\t.columns([\"state\", \"lease_expires_at\", \"collection_id\", \"content_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_work_operator\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_work\")\n\t\t.columns([\"collection_id\", \"state\", \"updated_at\", \"content_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_status_collection\")\n\t\t.ifNotExists()\n\t\t.unique()\n\t\t.on(\"_emdash_media_usage_index_status\")\n\t\t.columns([\"adapter_id\", \"scope_type\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_identity\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"source_type\", \"collection_id\", \"content_id\", \"source_variant\"])\n\t\t.execute();\n\n\tawait sql`\n\t\tDELETE FROM _emdash_media_usage_index_status\n\t\tWHERE adapter_id = ${CONTENT_ADAPTER_ID}\n\t\t\tAND scope_type = ${COLLECTION_SCOPE}\n\t\t\tAND (\n\t\t\t\t(\n\t\t\t\t\tcollection_id IS NULL\n\t\t\t\t\tAND NOT EXISTS (\n\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\tFROM _emdash_collections AS collection\n\t\t\t\t\t\tWHERE collection.slug = _emdash_media_usage_index_status.scope_key\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\tOR (\n\t\t\t\t\tcollection_id IS NOT NULL\n\t\t\t\t\tAND capture_state = 'installing'\n\t\t\t\t\tAND EXISTS (\n\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\tFROM _emdash_media_usage_activation AS activation\n\t\t\t\t\t\tWHERE activation.task_key = ${ACTIVATION_KEY}\n\t\t\t\t\t\t\tAND activation.state = 'expanded'\n\t\t\t\t\t)\n\t\t\t\t\tAND NOT EXISTS (\n\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\tFROM _emdash_collections AS collection\n\t\t\t\t\t\tWHERE collection.id = _emdash_media_usage_index_status.collection_id\n\t\t\t\t\t\t\tAND collection.slug = _emdash_media_usage_index_status.scope_key\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t`.execute(db);\n\n\tawait sql`\n\t\tUPDATE _emdash_media_usage_index_status\n\t\tSET collection_id = (\n\t\t\t\tSELECT collection.id\n\t\t\t\tFROM _emdash_collections AS collection\n\t\t\t\tWHERE collection.slug = _emdash_media_usage_index_status.scope_key\n\t\t\t),\n\t\t\treconciliation_required = 1,\n\t\t\tcapture_state = COALESCE(capture_state, 'installing')\n\t\tWHERE adapter_id = ${CONTENT_ADAPTER_ID}\n\t\t\tAND scope_type = ${COLLECTION_SCOPE}\n\t\t\tAND (\n\t\t\t\tcollection_id IS NULL\n\t\t\t\tOR capture_state IS NULL\n\t\t\t)\n\t\t\tAND EXISTS (\n\t\t\t\tSELECT 1\n\t\t\t\tFROM _emdash_collections AS collection\n\t\t\t\tWHERE collection.id = COALESCE(\n\t\t\t\t\t_emdash_media_usage_index_status.collection_id,\n\t\t\t\t\tcollection.id\n\t\t\t\t)\n\t\t\t\t\tAND collection.slug = _emdash_media_usage_index_status.scope_key\n\t\t\t)\n\t`.execute(db);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait assertRollbackIsEmptyAndInactive(db);\n\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_sources_identity\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_status_collection\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_work_operator\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_work_lease\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_work_due\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_work\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_activation\").ifExists().execute();\n\tif (isPostgres(db)) {\n\t\tawait sql`DROP FUNCTION IF EXISTS emdash_media_usage_capture_work()`.execute(db);\n\t}\n\n\tfor (const columnName of [\"identity_version\", \"collection_id\"] as const) {\n\t\tif (await columnExists(db, \"_emdash_media_usage_sources\", columnName)) {\n\t\t\tawait db.schema.alterTable(\"_emdash_media_usage_sources\").dropColumn(columnName).execute();\n\t\t}\n\t}\n\n\tfor (const columnName of [\n\t\t\"capture_state\",\n\t\t\"last_incremental_success_at\",\n\t\t\"reconciliation_required\",\n\t\t\"change_epoch\",\n\t\t\"collection_id\",\n\t] as const) {\n\t\tif (await columnExists(db, \"_emdash_media_usage_index_status\", columnName)) {\n\t\t\tawait db.schema\n\t\t\t\t.alterTable(\"_emdash_media_usage_index_status\")\n\t\t\t\t.dropColumn(columnName)\n\t\t\t\t.execute();\n\t\t}\n\t}\n}\n\nasync function addStatusColumns(db: Kysely<unknown>): Promise<void> {\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_index_status\", \"collection_id\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_index_status\")\n\t\t\t.addColumn(\"collection_id\", \"text\")\n\t\t\t.execute(),\n\t);\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_index_status\", \"change_epoch\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_index_status\")\n\t\t\t.addColumn(\"change_epoch\", \"bigint\", (column) => column.notNull().defaultTo(0))\n\t\t\t.execute(),\n\t);\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_index_status\", \"reconciliation_required\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_index_status\")\n\t\t\t.addColumn(\"reconciliation_required\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t\t.execute(),\n\t);\n\tawait addStatusTextColumn(db, \"last_incremental_success_at\");\n\tawait addStatusTextColumn(db, \"capture_state\");\n}\n\nasync function assertRollbackIsEmptyAndInactive(db: Kysely<unknown>): Promise<void> {\n\tif (await hasCaptureTriggers(db)) {\n\t\tthrow new Error(\"Cannot roll back media usage capture while capture triggers are installed\");\n\t}\n\n\tif (await tableExists(db, \"_emdash_media_usage_activation\")) {\n\t\tconst activation = await sql<{ state: string }>`\n\t\t\tSELECT state\n\t\t\tFROM _emdash_media_usage_activation\n\t\t\tWHERE task_key = ${ACTIVATION_KEY}\n\t\t`.execute(db);\n\t\tif (activation.rows[0] && activation.rows[0].state !== \"expanded\") {\n\t\t\tthrow new Error(\"Cannot roll back media usage capture after activation has started\");\n\t\t}\n\t}\n\n\tif (await tableExists(db, \"_emdash_media_usage_work\")) {\n\t\tconst work = await sql<{ present: number }>`\n\t\t\tSELECT 1 AS present FROM _emdash_media_usage_work LIMIT 1\n\t\t`.execute(db);\n\t\tif (work.rows.length > 0) {\n\t\t\tthrow new Error(\"Cannot roll back media usage capture while durable work exists\");\n\t\t}\n\t}\n\n\tconst sourceHasCollectionId = await columnExists(\n\t\tdb,\n\t\t\"_emdash_media_usage_sources\",\n\t\t\"collection_id\",\n\t);\n\tconst sourceHasIdentityVersion = await columnExists(\n\t\tdb,\n\t\t\"_emdash_media_usage_sources\",\n\t\t\"identity_version\",\n\t);\n\tif (sourceHasCollectionId || sourceHasIdentityVersion) {\n\t\tconst canonicalSources = sourceHasCollectionId\n\t\t\t? await sql<{ present: number }>`\n\t\t\t\t\tSELECT 1 AS present\n\t\t\t\t\tFROM _emdash_media_usage_sources\n\t\t\t\t\tWHERE collection_id IS NOT NULL\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(db)\n\t\t\t: await sql<{ present: number }>`\n\t\t\t\t\tSELECT 1 AS present\n\t\t\t\t\tFROM _emdash_media_usage_sources\n\t\t\t\t\tWHERE identity_version IS NOT NULL\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(db);\n\t\tif (canonicalSources.rows.length > 0) {\n\t\t\tthrow new Error(\"Cannot roll back media usage capture after canonical sources exist\");\n\t\t}\n\t\tif (sourceHasCollectionId && sourceHasIdentityVersion) {\n\t\t\tconst versionedSources = await sql<{ present: number }>`\n\t\t\t\tSELECT 1 AS present\n\t\t\t\tFROM _emdash_media_usage_sources\n\t\t\t\tWHERE identity_version IS NOT NULL\n\t\t\t\tLIMIT 1\n\t\t\t`.execute(db);\n\t\t\tif (versionedSources.rows.length > 0) {\n\t\t\t\tthrow new Error(\"Cannot roll back media usage capture after canonical sources exist\");\n\t\t\t}\n\t\t}\n\t}\n\n\tif (await columnExists(db, \"_emdash_media_usage_index_status\", \"capture_state\")) {\n\t\tconst lifecycle = await sql<{ present: number }>`\n\t\t\tSELECT 1 AS present FROM _emdash_media_usage_index_status\n\t\t\tWHERE capture_state IN ('active', 'deleting') LIMIT 1\n\t\t`.execute(db);\n\t\tif (lifecycle.rows.length > 0) throwRollbackLifecycleError();\n\t}\n\tif (await columnExists(db, \"_emdash_media_usage_index_status\", \"change_epoch\")) {\n\t\tconst epoch = await sql<{ present: number }>`\n\t\t\tSELECT 1 AS present FROM _emdash_media_usage_index_status\n\t\t\tWHERE change_epoch <> 0 LIMIT 1\n\t\t`.execute(db);\n\t\tif (epoch.rows.length > 0) throwRollbackLifecycleError();\n\t}\n\tif (await columnExists(db, \"_emdash_media_usage_index_status\", \"last_incremental_success_at\")) {\n\t\tconst success = await sql<{ present: number }>`\n\t\t\tSELECT 1 AS present FROM _emdash_media_usage_index_status\n\t\t\tWHERE last_incremental_success_at IS NOT NULL LIMIT 1\n\t\t`.execute(db);\n\t\tif (success.rows.length > 0) throwRollbackLifecycleError();\n\t}\n}\n\nfunction throwRollbackLifecycleError(): never {\n\tthrow new Error(\"Cannot roll back media usage capture while capture lifecycle state exists\");\n}\n\nasync function hasCaptureTriggers(db: Kysely<unknown>): Promise<boolean> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ present: boolean }>`\n\t\t\tSELECT EXISTS (\n\t\t\t\tSELECT 1\n\t\t\t\tFROM pg_trigger AS trigger\n\t\t\t\tINNER JOIN pg_class AS relation ON relation.oid = trigger.tgrelid\n\t\t\t\tINNER JOIN pg_namespace AS namespace ON namespace.oid = relation.relnamespace\n\t\t\t\tWHERE namespace.nspname = current_schema()\n\t\t\t\t\tAND NOT trigger.tgisinternal\n\t\t\t\t\tAND left(trigger.tgname, 10) = 'emdash_mu_'\n\t\t\t) AS present\n\t\t`.execute(db);\n\t\treturn result.rows[0]?.present === true;\n\t}\n\n\tconst result = await sql<{ present: number }>`\n\t\tSELECT 1 AS present\n\t\tFROM sqlite_master\n\t\tWHERE type = 'trigger' AND substr(name, 1, 10) = 'emdash_mu_'\n\t\tLIMIT 1\n\t`.execute(db);\n\treturn result.rows.length > 0;\n}\n\nasync function addStatusTextColumn(db: Kysely<unknown>, columnName: string): Promise<void> {\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_index_status\", columnName, () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_index_status\")\n\t\t\t.addColumn(columnName, \"text\")\n\t\t\t.execute(),\n\t);\n}\n\nasync function addSourceColumns(db: Kysely<unknown>): Promise<void> {\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_sources\", \"collection_id\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_sources\")\n\t\t\t.addColumn(\"collection_id\", \"text\")\n\t\t\t.execute(),\n\t);\n\tawait addColumnIfMissing(db, \"_emdash_media_usage_sources\", \"identity_version\", () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"_emdash_media_usage_sources\")\n\t\t\t.addColumn(\"identity_version\", \"integer\")\n\t\t\t.execute(),\n\t);\n}\n\nasync function addColumnIfMissing(\n\tdb: Kysely<unknown>,\n\ttableName: string,\n\tcolumnName: string,\n\taddColumn: () => Promise<void>,\n): Promise<void> {\n\tif (await columnExists(db, tableName, columnName)) return;\n\n\ttry {\n\t\tawait addColumn();\n\t} catch (error) {\n\t\tif (DUPLICATE_COLUMN_RE.test(deepErrorMessage(error))) {\n\t\t\tif (await columnExists(db, tableName, columnName)) return;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction sortableUtcTimestamp(db: Kysely<unknown>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`to_char(clock_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')`;\n\t}\n\treturn sql`(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`;\n}\n\nfunction deepErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst own = error.message ?? \"\";\n\t\tif (error.cause) {\n\t\t\tconst causeMessage = deepErrorMessage(error.cause);\n\t\t\treturn own ? `${own}: ${causeMessage}` : causeMessage;\n\t\t}\n\t\treturn own;\n\t}\n\tif (typeof error === \"string\") return error;\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\n/**\n * Migration: Rebuild FTS5 indexes as self-contained tables indexing\n * extracted Portable Text prose\n *\n * Background: FTS tables were external-content (`content='ec_<slug>'`),\n * which forces the index to mirror the raw column values — and Portable\n * Text fields store JSON, so the index was polluted with structural tokens\n * (`_type`, `span`, style values like `normal`, `_key` ULIDs). Searches for\n * those tokens matched nearly every document and snippets showed JSON\n * fragments.\n *\n * The fix rebuilds each search-enabled collection's FTS table as a\n * self-contained FTS5 table (no `content=` option) whose Portable Text\n * columns hold extracted prose — every JSON string under a `text`, `alt`,\n * `caption`, or `code` key — with sync triggers computing the same\n * extraction in SQL. The update trigger carries a WHEN guard so only real\n * value changes re-tokenize; shipping the guard inside this rebuild spares\n * existing sites a second full re-tokenization from a follow-up migration.\n * Self-contained tables also retire the external-content\n * `'delete'` choreography and its corruption modes (see migration 039).\n * The rebuilt table keeps the collection's configured `tokenize` from\n * search_config rather than resetting it to the default.\n *\n * The SQL emitted here MUST stay in lock-step with\n * `FTSManager.createTriggers` / `createFtsTable` / `populateFromContent` in\n * `src/search/fts-manager.ts`. If those change again, add a new migration\n * rather than editing this one — migrations are forward-only.\n *\n * Postgres: no-op. FTS5 is SQLite-only.\n *\n * D1: idempotent at the granularity we care about (drop-then-create +\n * repopulate with `INSERT OR REPLACE`, so concurrent migrators converge).\n * A partial apply that drops the FTS table without recreating it is healed\n * by the next `verifyAndRepairIndex` call at runtime.\n */\n\ninterface CollectionRow {\n\tslug: string;\n\tsearch_config: string | null;\n}\n\ninterface FieldRow {\n\tslug: string;\n\ttype: string;\n}\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!isSqlite(db)) return;\n\n\tconst collections = await sql<CollectionRow>`\n\t\tSELECT slug, search_config FROM _emdash_collections\n\t\tWHERE search_config IS NOT NULL\n\t`.execute(db);\n\n\tfor (const collection of collections.rows) {\n\t\tif (!isSearchEnabled(collection.search_config)) continue;\n\n\t\t// Defensive re-validation before raw SQL interpolation, mirroring 039.\n\t\ttry {\n\t\t\tvalidateIdentifier(collection.slug, \"collection slug\");\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`[migration 064] skipping FTS rebuild for collection \"${collection.slug}\": ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fields = await getSearchableFields(db, collection.slug);\n\t\tif (fields.length === 0) continue;\n\n\t\tawait rebuildIndex(db, collection.slug, fields, searchTokenizer(collection.search_config));\n\t}\n}\n\n/**\n * Forward-only. Down is a no-op: the FTS tables are managed by FTSManager\n * at runtime and the self-contained shape remains fully functional for\n * older code paths that only MATCH and join on id.\n */\nexport async function down(_db: Kysely<unknown>): Promise<void> {\n\t// no-op\n}\n\nfunction isSearchEnabled(searchConfig: string | null): boolean {\n\tif (!searchConfig) return false;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(searchConfig);\n\t\treturn (\n\t\t\ttypeof parsed === \"object\" &&\n\t\t\tparsed !== null &&\n\t\t\t\"enabled\" in parsed &&\n\t\t\tparsed.enabled === true\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Tokenizers this migration knows how to carry across the rebuild — a frozen\n * copy of SEARCH_TOKENIZERS as of this migration, not an import: a replay\n * after the live allowlist changes must not reinterpret configs this\n * migration never shipped with.\n */\nconst KNOWN_TOKENIZERS = [\"porter unicode61\", \"unicode61\", \"trigram\"];\n\n/**\n * Tokenizer for the rebuilt table, from the collection's search_config.\n * Values outside the allowlist (or unparsable config) fall back to the\n * default rather than reaching the raw CREATE VIRTUAL TABLE statement.\n */\nfunction searchTokenizer(searchConfig: string | null): string {\n\tif (!searchConfig) return \"porter unicode61\";\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(searchConfig);\n\t\tif (typeof parsed === \"object\" && parsed !== null && \"tokenize\" in parsed) {\n\t\t\tconst configured = KNOWN_TOKENIZERS.find((tokenizer) => tokenizer === parsed.tokenize);\n\t\t\tif (configured !== undefined) return configured;\n\t\t}\n\t} catch {\n\t\treturn \"porter unicode61\";\n\t}\n\treturn \"porter unicode61\";\n}\n\nasync function getSearchableFields(\n\tdb: Kysely<unknown>,\n\tcollectionSlug: string,\n): Promise<FieldRow[]> {\n\tconst rows = await sql<FieldRow>`\n\t\tSELECT f.slug, f.type FROM _emdash_fields f\n\t\tINNER JOIN _emdash_collections c ON c.id = f.collection_id\n\t\tWHERE c.slug = ${collectionSlug} AND f.searchable = 1\n\t`.execute(db);\n\n\tconst out: FieldRow[] = [];\n\tfor (const row of rows.rows) {\n\t\ttry {\n\t\t\tvalidateIdentifier(row.slug, \"searchable field name\");\n\t\t\tout.push(row);\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t`[migration 064] skipping invalid searchable field \"${row.slug}\" on collection \"${collectionSlug}\"`,\n\t\t\t);\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Indexed-value expression for one field; lock-step with FTSManager.searchValueExpr. */\nfunction searchValueExpr(ref: string, fieldType: string): string {\n\tif (fieldType !== \"portableText\") return ref;\n\treturn (\n\t\t`CASE WHEN ${ref} IS NULL THEN NULL ` +\n\t\t`WHEN json_valid(${ref}) AND json_type(${ref}) IN ('array', 'object') THEN (` +\n\t\t`SELECT group_concat(j.value, ' ') FROM json_tree(${ref}) AS j ` +\n\t\t`WHERE j.key IN ('text', 'alt', 'caption', 'code') AND j.type = 'text') ` +\n\t\t`ELSE ${ref} END`\n\t);\n}\n\nasync function rebuildIndex(\n\tdb: Kysely<unknown>,\n\tcollectionSlug: string,\n\tfields: FieldRow[],\n\ttokenizer: string,\n): Promise<void> {\n\tconst ftsTable = `_emdash_fts_${collectionSlug}`;\n\tconst contentTable = `ec_${collectionSlug}`;\n\tconst slugs = fields.map((f) => f.slug);\n\tconst columnList = [\"id UNINDEXED\", \"locale UNINDEXED\", ...slugs].join(\", \");\n\tconst fieldList = slugs.join(\", \");\n\tconst newValueList = fields.map((f) => searchValueExpr(`NEW.${f.slug}`, f.type)).join(\", \");\n\t// The WHEN guard compares raw column values (null-safe IS NOT) so the\n\t// update trigger fires only when an indexed value, the row's locale, or\n\t// its trash state actually changed; without it every UPDATE re-tokenizes\n\t// the whole document. deleted_at must stay in the guard or trash and\n\t// restore stop syncing the index.\n\tconst changedCondition = [\"deleted_at\", \"locale\", ...slugs]\n\t\t.map((f) => `OLD.${f} IS NOT NEW.${f}`)\n\t\t.join(\" OR \");\n\t// Table-qualified: a bare column reference inside the json_tree extraction\n\t// subquery binds to json_tree's own key/value/type/... columns.\n\tconst selectValueList = fields\n\t\t.map((f) => searchValueExpr(`\"${contentTable}\".\"${f.slug}\"`, f.type))\n\t\t.join(\", \");\n\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_insert\"`).execute(db);\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_update\"`).execute(db);\n\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_delete\"`).execute(db);\n\tawait sql.raw(`DROP TABLE IF EXISTS \"${ftsTable}\"`).execute(db);\n\n\tawait sql\n\t\t.raw(`\n\t\tCREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTable}\" USING fts5(\n\t\t\t${columnList},\n\t\t\ttokenize='${tokenizer}'\n\t\t)\n\t`)\n\t\t.execute(db);\n\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_insert\"\n\t\tAFTER INSERT ON \"${contentTable}\"\n\t\tWHEN NEW.deleted_at IS NULL\n\t\tBEGIN\n\t\t\tINSERT OR REPLACE INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tVALUES (NEW.rowid, NEW.id, NEW.locale, ${newValueList});\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_update\"\n\t\tAFTER UPDATE ON \"${contentTable}\"\n\t\tWHEN ${changedCondition}\n\t\tBEGIN\n\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tSELECT NEW.rowid, NEW.id, NEW.locale, ${newValueList}\n\t\t\tWHERE NEW.deleted_at IS NULL;\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\tawait sql\n\t\t.raw(`\n\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_delete\"\n\t\tAFTER DELETE ON \"${contentTable}\"\n\t\tBEGIN\n\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\tEND\n\t`)\n\t\t.execute(db);\n\n\tawait sql\n\t\t.raw(`\n\t\tINSERT OR REPLACE INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\tSELECT rowid, id, locale, ${selectValueList} FROM \"${contentTable}\"\n\t\tWHERE deleted_at IS NULL\n\t`)\n\t\t.execute(db);\n}\n","import { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { isPostgres } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_collection_deletions\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"collection_id\", \"text\", (column) => column.notNull().primaryKey())\n\t\t.addColumn(\"collection_slug\", \"text\", (column) => column.notNull().unique())\n\t\t.addColumn(\"force_delete\", \"integer\", (column) => column.notNull())\n\t\t.addColumn(\"state\", \"text\", (column) => column.notNull().defaultTo(\"pending\"))\n\t\t.addColumn(\"phase\", \"text\", (column) => column.notNull().defaultTo(\"fence\"))\n\t\t.addColumn(\"work_cursor\", \"text\")\n\t\t.addColumn(\"source_key\", \"text\")\n\t\t.addColumn(\"occurrence_cursor\", \"text\")\n\t\t.addColumn(\"attempt_count\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t.addColumn(\"next_attempt_at\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"lease_token\", \"text\")\n\t\t.addColumn(\"lease_expires_at\", \"text\")\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.addColumn(\"updated_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_collection_deletions_due\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_collection_deletions\")\n\t\t.columns([\"state\", \"next_attempt_at\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_collection_deletions_lease\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_collection_deletions\")\n\t\t.columns([\"state\", \"lease_expires_at\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_collection_deletions_operator\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_collection_deletions\")\n\t\t.columns([\"state\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_sources_collection_cursor\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_sources\")\n\t\t.columns([\"source_type\", \"collection_id\", \"source_key\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_source_cursor\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage\")\n\t\t.columns([\"source_key\", \"id\"])\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst deletion = await sql<{ present: number }>`\n\t\tSELECT 1 AS present\n\t\tFROM _emdash_media_usage_collection_deletions\n\t\tLIMIT 1\n\t`.execute(db);\n\tif (deletion.rows.length > 0) {\n\t\tthrow new Error(\"Cannot roll back while durable collection deletion evidence exists\");\n\t}\n\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_source_cursor\").ifExists().execute();\n\tawait db.schema\n\t\t.dropIndex(\"idx__emdash_media_usage_sources_collection_cursor\")\n\t\t.ifExists()\n\t\t.execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_collection_deletions\").ifExists().execute();\n}\n\nfunction sortableUtcTimestamp(db: Kysely<unknown>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`to_char(clock_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')`;\n\t}\n\treturn sql`(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`;\n}\n","import { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { columnExists, isPostgres, tableExists } from \"../dialect-helpers.js\";\n\nconst ACTIVATION_KEY = \"incremental_capture\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"_emdash_media_usage_reconciliations\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"collection_id\", \"text\", (column) => column.notNull().primaryKey())\n\t\t.addColumn(\"collection_slug\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"run_token\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"target_epoch\", \"bigint\")\n\t\t.addColumn(\"field_fingerprint\", \"text\")\n\t\t.addColumn(\"state\", \"text\", (column) => column.notNull().defaultTo(\"pending\"))\n\t\t.addColumn(\"phase\", \"text\", (column) => column.notNull().defaultTo(\"scan\"))\n\t\t.addColumn(\"scan_cursor\", \"text\")\n\t\t.addColumn(\"scan_upper_id\", \"text\")\n\t\t.addColumn(\"source_cursor\", \"text\")\n\t\t.addColumn(\"source_upper_key\", \"text\")\n\t\t.addColumn(\"attempt_count\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t.addColumn(\"next_attempt_at\", \"text\", (column) => column.notNull())\n\t\t.addColumn(\"lease_token\", \"text\")\n\t\t.addColumn(\"lease_expires_at\", \"text\")\n\t\t.addColumn(\"last_error_code\", \"text\")\n\t\t.addColumn(\"created_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.addColumn(\"updated_at\", \"text\", (column) =>\n\t\t\tcolumn.notNull().defaultTo(sortableUtcTimestamp(db)),\n\t\t)\n\t\t.execute();\n\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_reconciliations_due\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_reconciliations\")\n\t\t.columns([\"state\", \"next_attempt_at\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_reconciliations_lease\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_reconciliations\")\n\t\t.columns([\"state\", \"lease_expires_at\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_reconciliations_failed\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_reconciliations\")\n\t\t.columns([\"state\", \"updated_at\", \"collection_id\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx__emdash_media_usage_status_reconciliation\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_media_usage_index_status\")\n\t\t.columns([\n\t\t\t\"adapter_id\",\n\t\t\t\"scope_type\",\n\t\t\t\"capture_state\",\n\t\t\t\"reconciliation_required\",\n\t\t\t\"collection_id\",\n\t\t])\n\t\t.execute();\n\n\tif (!(await columnExists(db, \"_emdash_media_usage_activation\", \"media_usage_maintenance_turn\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_media_usage_activation\")\n\t\t\t.addColumn(\"media_usage_maintenance_turn\", \"integer\", (column) =>\n\t\t\t\tcolumn.notNull().defaultTo(2),\n\t\t\t)\n\t\t\t.execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await tableExists(db, \"_emdash_media_usage_reconciliations\")) {\n\t\tconst evidence = await sql<{ present: number }>`\n\t\t\tSELECT 1 AS present\n\t\t\tFROM _emdash_media_usage_reconciliations\n\t\t\tLIMIT 1\n\t\t`.execute(db);\n\t\tif (evidence.rows.length > 0) {\n\t\t\tthrow new Error(\"Cannot roll back while durable reconciliation evidence exists\");\n\t\t}\n\t}\n\n\tconst activation = await sql<{ state: string }>`\n\t\tSELECT state\n\t\tFROM _emdash_media_usage_activation\n\t\tWHERE task_key = ${ACTIVATION_KEY}\n\t`.execute(db);\n\tif (activation.rows[0]?.state !== \"expanded\") {\n\t\tthrow new Error(\"Cannot roll back media usage reconciliation after activation has started\");\n\t}\n\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_status_reconciliation\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_reconciliations_failed\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_reconciliations_lease\").ifExists().execute();\n\tawait db.schema.dropIndex(\"idx__emdash_media_usage_reconciliations_due\").ifExists().execute();\n\tawait db.schema.dropTable(\"_emdash_media_usage_reconciliations\").ifExists().execute();\n\tif (await columnExists(db, \"_emdash_media_usage_activation\", \"media_usage_maintenance_turn\")) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_media_usage_activation\")\n\t\t\t.dropColumn(\"media_usage_maintenance_turn\")\n\t\t\t.execute();\n\t}\n}\n\nfunction sortableUtcTimestamp(db: Kysely<unknown>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`to_char(clock_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')`;\n\t}\n\treturn sql`(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`;\n}\n","import { sql, type Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\nconst FIELD_ID_PATTERN = /^[0-9A-Z]{26}$/;\n\n/** Mark custom fields whose structured list queries are backed by a physical index. */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_fields\", \"indexed\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_fields\")\n\t\t\t.addColumn(\"indexed\", \"integer\", (column) => column.notNull().defaultTo(0))\n\t\t\t.execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_fields\", \"indexed\"))) {\n\t\treturn;\n\t}\n\n\tconst indexedFields = await sql<{ id: string }>`\n\t\tSELECT id FROM _emdash_fields WHERE indexed = 1\n\t`.execute(db);\n\n\tfor (const field of indexedFields.rows) {\n\t\tif (!FIELD_ID_PATTERN.test(field.id)) {\n\t\t\tthrow new Error(`Invalid indexed field id \"${field.id}\"`);\n\t\t}\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_cf_${field.id.toLowerCase()}`)}\n\t\t`.execute(db);\n\t\tawait sql`\n\t\t\tDROP INDEX IF EXISTS ${sql.ref(`idx_cf_${field.id.toLowerCase()}_loc`)}\n\t\t`.execute(db);\n\t}\n\n\tawait db.schema.alterTable(\"_emdash_fields\").dropColumn(\"indexed\").execute();\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\nimport { validateIdentifier } from \"../validate.js\";\n\nconst LEGACY_DENORM_INDEXES = [\n\t\"idx_content_taxonomies_pub\",\n\t\"idx_content_taxonomies_crt\",\n\t\"idx_content_taxonomies_loc_pub\",\n\t\"idx_content_taxonomies_loc_crt\",\n] as const;\n\n/**\n * Store the content translation_group in content_taxonomies.entry_id.\n * Existing per-locale rows are merged into one assignment per content group\n * and term group. Rows whose content table or content entry no longer exists\n * are left untouched.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\tfor (const tableName of tableNames) {\n\t\tvalidateIdentifier(tableName, \"content table name\");\n\t\tconst collection = tableName.slice(\"ec_\".length);\n\n\t\tawait sql`\n\t\t\tINSERT INTO content_taxonomies (collection, entry_id, taxonomy_id)\n\t\t\tSELECT DISTINCT ${collection}, content.translation_group, pivot.taxonomy_id\n\t\t\tFROM content_taxonomies AS pivot\n\t\t\tINNER JOIN ${sql.ref(tableName)} AS content ON content.id = pivot.entry_id\n\t\t\tWHERE pivot.collection = ${collection}\n\t\t\t\tAND content.translation_group IS NOT NULL\n\t\t\tON CONFLICT (collection, entry_id, taxonomy_id) DO NOTHING\n\t\t`.execute(db);\n\n\t\tawait sql`\n\t\t\tDELETE FROM content_taxonomies\n\t\t\tWHERE collection = ${collection}\n\t\t\t\tAND entry_id IN (\n\t\t\t\t\tSELECT id\n\t\t\t\t\tFROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE translation_group IS NOT NULL AND id != translation_group\n\t\t\t\t)\n\t\t`.execute(db);\n\t}\n\n\tfor (const indexName of LEGACY_DENORM_INDEXES) {\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(indexName)}`.execute(db);\n\t}\n\tawait db.schema\n\t\t.createIndex(\"idx_content_taxonomies_group_lookup\")\n\t\t.ifNotExists()\n\t\t.on(\"content_taxonomies\")\n\t\t.columns([\"taxonomy_id\", \"collection\", \"entry_id\"])\n\t\t.execute();\n}\n\n/** The collapsed per-locale rows cannot be reconstructed. */\nexport async function down(_db: Kysely<unknown>): Promise<void> {\n\t// no-op\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\n/**\n * Migration: configurable title and date fields for collections\n *\n * Adds `title_field` and `date_field` columns to `_emdash_collections` so a\n * collection can override which field powers the Title column and which field\n * powers the Date column in the admin content list. Both are nullable — NULL\n * preserves the current defaults (title-style display, last-updated date).\n *\n * Column adds/drops are guarded by `columnExists`: D1 has no transactions, so a\n * migration can partially apply without being recorded and later re-run.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_collections\", \"title_field\"))) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_collections\n\t\t\tADD COLUMN title_field TEXT\n\t\t`.execute(db);\n\t}\n\tif (!(await columnExists(db, \"_emdash_collections\", \"date_field\"))) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_collections\n\t\t\tADD COLUMN date_field TEXT\n\t\t`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"_emdash_collections\", \"date_field\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_collections\n\t\t\tDROP COLUMN date_field\n\t\t`.execute(db);\n\t}\n\tif (await columnExists(db, \"_emdash_collections\", \"title_field\")) {\n\t\tawait sql`\n\t\t\tALTER TABLE _emdash_collections\n\t\t\tDROP COLUMN title_field\n\t\t`.execute(db);\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!(await columnExists(db, \"_emdash_collections\", \"routable\"))) {\n\t\tawait db.schema\n\t\t\t.alterTable(\"_emdash_collections\")\n\t\t\t.addColumn(\"routable\", \"integer\", (col) => col.notNull().defaultTo(1))\n\t\t\t.execute();\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"_emdash_collections\", \"routable\")) {\n\t\tawait db.schema.alterTable(\"_emdash_collections\").dropColumn(\"routable\").execute();\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite, tableExists } from \"../dialect-helpers.js\";\n\n/**\n * Restore `_emdash_content_bylines` where migration 040's SQLite rebuild\n * stopped between dropping the old table and renaming the staged copy.\n *\n * 040 guards its rebuild on `PRAGMA foreign_key_list`, which returns no rows\n * for a missing table, so a retry after that partial run skips the rename and\n * leaves `_emdash_content_bylines_new` behind with the credits inside. The\n * indexes went with the dropped table.\n *\n * The Postgres path of 040 alters the table in place, so this is a no-op there.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tif (!isSqlite(db)) return;\n\n\tif (!(await tableExists(db, \"_emdash_content_bylines\"))) {\n\t\tif (!(await tableExists(db, \"_emdash_content_bylines_new\"))) return;\n\t\tawait sql`ALTER TABLE _emdash_content_bylines_new RENAME TO _emdash_content_bylines`.execute(\n\t\t\tdb,\n\t\t);\n\t}\n\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_content\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.columns([\"collection_slug\", \"content_id\", \"sort_order\"])\n\t\t.execute();\n\tawait db.schema\n\t\t.createIndex(\"idx_content_bylines_byline\")\n\t\t.ifNotExists()\n\t\t.on(\"_emdash_content_bylines\")\n\t\t.column(\"byline_id\")\n\t\t.execute();\n}\n\nexport async function down(_db: Kysely<unknown>): Promise<void> {\n\t// no-op\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\nconst DUPLICATE_COLUMN_RE = /(?:duplicate column|column .* already exists|already exists.*column)/i;\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema\n\t\t.createTable(\"media_folders\")\n\t\t.ifNotExists()\n\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t.addColumn(\"name\", \"text\", (col) => col.notNull())\n\t\t.addColumn(\"name_key\", \"text\", (col) => col.notNull().unique())\n\t\t.execute();\n\n\tawait addFolderColumnIfMissing(db, () =>\n\t\tdb.schema\n\t\t\t.alterTable(\"media\")\n\t\t\t.addColumn(\"folder_id\", \"text\", (col) =>\n\t\t\t\tcol.references(\"media_folders.id\").onDelete(\"set null\"),\n\t\t\t)\n\t\t\t.execute(),\n\t);\n\n\tawait db.schema\n\t\t.createIndex(\"idx_media_folder_id\")\n\t\t.ifNotExists()\n\t\t.on(\"media\")\n\t\t.column(\"folder_id\")\n\t\t.execute();\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tawait db.schema.dropIndex(\"idx_media_folder_id\").ifExists().execute();\n\tif (await columnExists(db, \"media\", \"folder_id\")) {\n\t\tawait db.schema.alterTable(\"media\").dropColumn(\"folder_id\").execute();\n\t}\n\tawait db.schema.dropTable(\"media_folders\").ifExists().execute();\n}\n\nasync function addFolderColumnIfMissing(\n\tdb: Kysely<unknown>,\n\taddColumn: () => Promise<void>,\n): Promise<void> {\n\tif (await columnExists(db, \"media\", \"folder_id\")) return;\n\n\ttry {\n\t\tawait addColumn();\n\t} catch (error) {\n\t\tif (DUPLICATE_COLUMN_RE.test(deepErrorMessage(error))) {\n\t\t\tif (await columnExists(db, \"media\", \"folder_id\")) return;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction deepErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst own = error.message ?? \"\";\n\t\tif (error.cause) {\n\t\t\tconst causeMessage = deepErrorMessage(error.cause);\n\t\t\treturn own ? `${own}: ${causeMessage}` : causeMessage;\n\t\t}\n\t\treturn own;\n\t}\n\tif (typeof error === \"string\") return error;\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport { columnExists } from \"../dialect-helpers.js\";\n\nconst DUPLICATE_COLUMN_RE = /(?:duplicate column|column .* already exists|already exists.*column)/i;\n\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tawait addFocalColumnIfMissing(db, \"focal_x\", () =>\n\t\tdb.schema.alterTable(\"media\").addColumn(\"focal_x\", \"real\").execute(),\n\t);\n\tawait addFocalColumnIfMissing(db, \"focal_y\", () =>\n\t\tdb.schema.alterTable(\"media\").addColumn(\"focal_y\", \"real\").execute(),\n\t);\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tif (await columnExists(db, \"media\", \"focal_y\")) {\n\t\tawait db.schema.alterTable(\"media\").dropColumn(\"focal_y\").execute();\n\t}\n\tif (await columnExists(db, \"media\", \"focal_x\")) {\n\t\tawait db.schema.alterTable(\"media\").dropColumn(\"focal_x\").execute();\n\t}\n}\n\nexport async function addFocalColumnIfMissing(\n\tdb: Kysely<unknown>,\n\tcolumn: \"focal_x\" | \"focal_y\",\n\taddColumn: () => Promise<void>,\n): Promise<void> {\n\tif (await columnExists(db, \"media\", column)) return;\n\n\ttry {\n\t\tawait addColumn();\n\t} catch (error) {\n\t\tif (DUPLICATE_COLUMN_RE.test(deepErrorMessage(error))) {\n\t\t\tif (await columnExists(db, \"media\", column)) return;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction deepErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst own = error.message ?? \"\";\n\t\tif (error.cause) {\n\t\t\tconst causeMessage = deepErrorMessage(error.cause);\n\t\t\treturn own ? `${own}: ${causeMessage}` : causeMessage;\n\t\t}\n\t\treturn own;\n\t}\n\tif (typeof error === \"string\") return error;\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\n\n/**\n * Migration: replace the single-column partial `scheduled_at` index on content\n * tables with a `(deleted_at, scheduled_at)` composite.\n *\n * The scheduled-publishing sweep filters `scheduled_at` by range and\n * `deleted_at IS NULL`, ordered by `scheduled_at`. A `scheduled_at`-only index\n * cannot satisfy the soft-delete term, so a stats-blind planner seeks a\n * `deleted_at`-leading composite instead and reads every live row. Leading with\n * `deleted_at` lets one index serve the equality, the range, and the ORDER BY.\n * D1 never has `sqlite_stat1`, so the index shape is the only lever.\n *\n * The partial predicate from migration 030 is kept so the index stays\n * proportional to scheduled content rather than to the table.\n *\n * Forward-only and idempotent (`IF NOT EXISTS`).\n *\n * The short `del_sched` suffix keeps the name inside Postgres's 63-byte\n * identifier limit for long collection slugs. Keep it identical to the name in\n * `schema/registry.ts`.\n */\nexport async function up(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\t// D1 DDL is non-transactional: create the replacement before dropping the\n\t\t// old index so an interrupted migration always leaves a scheduled_at index\n\t\t// in place.\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${sql.ref(`idx_${tableName}_del_sched`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t`.execute(db);\n\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_scheduled`)}`.execute(db);\n\t}\n}\n\nexport async function down(db: Kysely<unknown>): Promise<void> {\n\tconst tableNames = await listTablesLike(db, \"ec_%\");\n\n\tfor (const tableName of tableNames) {\n\t\tawait sql`\n\t\t\tCREATE INDEX IF NOT EXISTS ${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(db);\n\n\t\tawait sql`DROP INDEX IF EXISTS ${sql.ref(`idx_${tableName}_del_sched`)}`.execute(db);\n\t}\n}\n","import { type Kysely, sql } from \"kysely\";\nimport { type Migration, type MigrationProvider, Migrator } from \"kysely/migration\";\n\nimport { MIGRATION_LOCK_BUSY_MESSAGE } from \"../pg-migration-lock.js\";\nimport type { Database } from \"../types.js\";\n// Import migrations statically for bundling\nimport * as m001 from \"./001_initial.js\";\nimport * as m002 from \"./002_media_status.js\";\nimport * as m003 from \"./003_schema_registry.js\";\nimport * as m004 from \"./004_plugins.js\";\nimport * as m005 from \"./005_menus.js\";\nimport * as m006 from \"./006_taxonomy_defs.js\";\nimport * as m007 from \"./007_widgets.js\";\nimport * as m008 from \"./008_auth.js\";\nimport * as m009 from \"./009_user_disabled.js\";\nimport * as m011 from \"./011_sections.js\";\nimport * as m012 from \"./012_search.js\";\nimport * as m013 from \"./013_scheduled_publishing.js\";\nimport * as m014 from \"./014_draft_revisions.js\";\nimport * as m015 from \"./015_indexes.js\";\nimport * as m016 from \"./016_api_tokens.js\";\nimport * as m017 from \"./017_authorization_codes.js\";\nimport * as m018 from \"./018_seo.js\";\nimport * as m019 from \"./019_i18n.js\";\nimport * as m020 from \"./020_collection_url_pattern.js\";\nimport * as m021 from \"./021_remove_section_categories.js\";\nimport * as m022 from \"./022_marketplace_plugin_state.js\";\nimport * as m023 from \"./023_plugin_metadata.js\";\nimport * as m024 from \"./024_media_placeholders.js\";\nimport * as m025 from \"./025_oauth_clients.js\";\nimport * as m026 from \"./026_cron_tasks.js\";\nimport * as m027 from \"./027_comments.js\";\nimport * as m028 from \"./028_drop_author_url.js\";\nimport * as m029 from \"./029_redirects.js\";\nimport * as m030 from \"./030_widen_scheduled_index.js\";\nimport * as m031 from \"./031_bylines.js\";\nimport * as m032 from \"./032_rate_limits.js\";\nimport * as m033 from \"./033_optimize_content_indexes.js\";\nimport * as m034 from \"./034_published_at_index.js\";\nimport * as m035 from \"./035_bounded_404_log.js\";\nimport * as m036 from \"./036_i18n_menus_and_taxonomies.js\";\nimport * as m037 from \"./037_credential_algorithm.js\";\nimport * as m038 from \"./038_registry_plugin_state.js\";\nimport * as m039 from \"./039_fix_fts5_triggers.js\";\nimport * as m040 from \"./040_byline_i18n.js\";\nimport * as m041 from \"./041_content_locale_list_index.js\";\nimport * as m042 from \"./042_byline_fields.js\";\nimport * as m043 from \"./043_content_references.js\";\nimport * as m044 from \"./044_comment_reactions.js\";\nimport * as m045 from \"./045_taxonomy_parent_group.js\";\nimport * as m046 from \"./046_media_usage_index.js\";\nimport * as m047 from \"./047_restore_taxonomy_parent_index.js\";\nimport * as m048 from \"./048_restore_content_taxonomies_term_index.js\";\nimport * as m049 from \"./049_taxonomies_name_locale_index.js\";\nimport * as m050 from \"./050_media_usage_index_status.js\";\nimport * as m051 from \"./051_content_taxonomies_denorm.js\";\nimport * as m052 from \"./052_media_usage_read_index.js\";\nimport * as m053 from \"./053_plugin_mcp_tools.js\";\nimport * as m054 from \"./054_media_upload_attempts.js\";\nimport * as m055 from \"./055_content_translation_group_locale_index.js\";\nimport * as m056 from \"./056_taxonomy_term_sort_order.js\";\nimport * as m057 from \"./057_collection_hidden.js\";\nimport * as m058 from \"./058_collection_sort_order.js\";\nimport * as m059 from \"./059_revision_prune_queue.js\";\nimport * as m060 from \"./060_collection_admin_config.js\";\nimport * as m061 from \"./061_media_usage_cleanup.js\";\nimport * as m062 from \"./062_media_usage_cleanup_fence.js\";\nimport * as m063 from \"./063_media_usage_incremental_work.js\";\nimport * as m064 from \"./064_fts_plain_text.js\";\nimport * as m065 from \"./065_media_usage_collection_deletion.js\";\nimport * as m066 from \"./066_media_usage_reconciliation.js\";\nimport * as m067 from \"./067_indexed_content_fields.js\";\nimport * as m068 from \"./068_content_taxonomy_entry_groups.js\";\nimport * as m069 from \"./069_collection_title_date_fields.js\";\nimport * as m070 from \"./070_collection_routable.js\";\nimport * as m071 from \"./071_restore_content_bylines_table.js\";\nimport * as m072 from \"./072_media_folders.js\";\nimport * as m073 from \"./073_media_focal_point.js\";\nimport * as m074 from \"./074_content_deleted_scheduled_index.js\";\n\nconst MIGRATIONS: Readonly<Record<string, Migration>> = Object.freeze({\n\t\"001_initial\": m001,\n\t\"002_media_status\": m002,\n\t\"003_schema_registry\": m003,\n\t\"004_plugins\": m004,\n\t\"005_menus\": m005,\n\t\"006_taxonomy_defs\": m006,\n\t\"007_widgets\": m007,\n\t\"008_auth\": m008,\n\t\"009_user_disabled\": m009,\n\t\"011_sections\": m011,\n\t\"012_search\": m012,\n\t\"013_scheduled_publishing\": m013,\n\t\"014_draft_revisions\": m014,\n\t\"015_indexes\": m015,\n\t\"016_api_tokens\": m016,\n\t\"017_authorization_codes\": m017,\n\t\"018_seo\": m018,\n\t\"019_i18n\": m019,\n\t\"020_collection_url_pattern\": m020,\n\t\"021_remove_section_categories\": m021,\n\t\"022_marketplace_plugin_state\": m022,\n\t\"023_plugin_metadata\": m023,\n\t\"024_media_placeholders\": m024,\n\t\"025_oauth_clients\": m025,\n\t\"026_cron_tasks\": m026,\n\t\"027_comments\": m027,\n\t\"028_drop_author_url\": m028,\n\t\"029_redirects\": m029,\n\t\"030_widen_scheduled_index\": m030,\n\t\"031_bylines\": m031,\n\t\"032_rate_limits\": m032,\n\t\"033_optimize_content_indexes\": m033,\n\t\"034_published_at_index\": m034,\n\t\"035_bounded_404_log\": m035,\n\t\"036_i18n_menus_and_taxonomies\": m036,\n\t\"037_credential_algorithm\": m037,\n\t\"038_registry_plugin_state\": m038,\n\t\"039_fix_fts5_triggers\": m039,\n\t\"040_byline_i18n\": m040,\n\t\"041_content_locale_list_index\": m041,\n\t\"042_byline_fields\": m042,\n\t\"043_content_references\": m043,\n\t\"044_comment_reactions\": m044,\n\t\"045_taxonomy_parent_group\": m045,\n\t\"046_media_usage_index\": m046,\n\t\"047_restore_taxonomy_parent_index\": m047,\n\t\"048_restore_content_taxonomies_term_index\": m048,\n\t\"049_taxonomies_name_locale_index\": m049,\n\t\"050_media_usage_index_status\": m050,\n\t\"051_content_taxonomies_denorm\": m051,\n\t\"052_media_usage_read_index\": m052,\n\t\"053_plugin_mcp_tools\": m053,\n\t\"054_media_upload_attempts\": m054,\n\t\"055_content_translation_group_locale_index\": m055,\n\t\"056_taxonomy_term_sort_order\": m056,\n\t\"057_collection_hidden\": m057,\n\t\"058_collection_sort_order\": m058,\n\t\"059_revision_prune_queue\": m059,\n\t\"060_collection_admin_config\": m060,\n\t\"061_media_usage_cleanup\": m061,\n\t\"062_media_usage_cleanup_fence\": m062,\n\t\"063_media_usage_incremental_work\": m063,\n\t\"064_fts_plain_text\": m064,\n\t\"065_media_usage_collection_deletion\": m065,\n\t\"066_media_usage_reconciliation\": m066,\n\t\"067_indexed_content_fields\": m067,\n\t\"068_content_taxonomy_entry_groups\": m068,\n\t\"069_collection_title_date_fields\": m069,\n\t\"070_collection_routable\": m070,\n\t\"071_restore_content_bylines_table\": m071,\n\t\"072_media_folders\": m072,\n\t\"073_media_focal_point\": m073,\n\t\"074_content_deleted_scheduled_index\": m074,\n});\n\n/** Ordered names from the statically registered migration set. */\nexport const MIGRATION_NAMES: readonly string[] = Object.freeze(Object.keys(MIGRATIONS));\n\n/** Total number of registered migrations. Exported for use in tests. */\nexport const MIGRATION_COUNT = MIGRATION_NAMES.length;\n\n/**\n * Migration provider that uses statically imported migrations.\n * This approach works well with bundlers and avoids filesystem access.\n */\nclass StaticMigrationProvider implements MigrationProvider {\n\tasync getMigrations(): Promise<Record<string, Migration>> {\n\t\treturn MIGRATIONS;\n\t}\n}\n\nexport interface MigrationStatus {\n\tapplied: string[];\n\tpending: string[];\n}\n\nexport interface ExactMigrationStatus {\n\tknownApplied: string[];\n\tpending: string[];\n\tunknownApplied: string[];\n}\n\n/**\n * Thrown when another instance held the migration lock for the whole wait\n * window. This is NOT a migration failure — the holder may simply be slow\n * (e.g. many pending migrations over a remote Postgres connection) — so\n * callers with failure-backoff logic (`getDatabase` in emdash-runtime.ts)\n * exempt it: the next request waits again instead of backing off, and init\n * recovers as soon as the holder finishes.\n */\nexport class ConcurrentMigrationTimeoutError extends Error {\n\tconstructor(waitMs: number) {\n\t\tsuper(\n\t\t\t`Timed out waiting for another instance's migrations: the migration lock was still held after ${waitMs}ms. ` +\n\t\t\t\t\"It may still be applying migrations, or its migration may be failing repeatedly.\",\n\t\t);\n\t\tthis.name = \"ConcurrentMigrationTimeoutError\";\n\t}\n}\n\n/** Custom migration table name */\nconst MIGRATION_TABLE = \"_emdash_migrations\";\nconst MIGRATION_LOCK_TABLE = \"_emdash_migrations_lock\";\n\nexport interface MigrationOptions {\n\tmigrationTableSchema?: string;\n\t/**\n\t * Override how long to wait for a concurrent migrator to finish before\n\t * giving up. Defaults to MIGRATION_RACE_WAIT_MS; tests shorten it so the\n\t * give-up path doesn't take 10 seconds per case.\n\t */\n\traceWaitMs?: number;\n}\n\nexport function createMigrator(db: Kysely<Database>, options?: MigrationOptions): Migrator {\n\treturn new Migrator({\n\t\tdb,\n\t\tprovider: new StaticMigrationProvider(),\n\t\tmigrationTableName: MIGRATION_TABLE,\n\t\tmigrationLockTableName: MIGRATION_LOCK_TABLE,\n\t\tmigrationTableSchema: options?.migrationTableSchema,\n\t});\n}\n\n/**\n * Get migration status\n */\nexport async function getMigrationStatus(\n\tdb: Kysely<Database>,\n\toptions?: MigrationOptions,\n): Promise<MigrationStatus> {\n\tconst migrator = createMigrator(db, options);\n\n\tconst migrations = await migrator.getMigrations();\n\n\tconst applied: string[] = [];\n\tconst pending: string[] = [];\n\n\tfor (const migration of migrations) {\n\t\tif (migration.executedAt) {\n\t\t\tapplied.push(migration.name);\n\t\t} else {\n\t\t\tpending.push(migration.name);\n\t\t}\n\t}\n\n\treturn { applied, pending };\n}\n\n/** Pattern for escaping special regex characters. Matches the shared helper in `database/repositories/content.ts`. */\nconst REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\\]\\\\]/g;\n\n/** Escape special regex characters so a string can be embedded literally in `new RegExp()`. */\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(REGEX_ESCAPE_PATTERN, \"\\\\$&\");\n}\n\n/**\n * Pattern used to detect the concurrent-migration race. The Kysely\n * `SqliteAdapter.acquireMigrationLock` is a no-op (inherited by `kysely-d1`\n * and our `EmDashD1Dialect`), so two isolates running migrations against the\n * same database can both attempt `INSERT INTO _emdash_migrations` for the\n * same migration name. The losing insert fails with a UNIQUE constraint\n * error, which is benign: the other isolate is applying the same schema.\n *\n * We match on the table name (not the full error text) because different\n * SQLite drivers phrase the message differently\n * (`UNIQUE constraint failed: _emdash_migrations.name` for file-backed SQLite,\n * `D1_ERROR: UNIQUE constraint failed: _emdash_migrations.name: SQLITE_CONSTRAINT`\n * for D1, etc.). The pattern is built from `MIGRATION_TABLE` so a rename\n * cannot silently disable race detection.\n */\nconst MIGRATION_RACE_PATTERN = new RegExp(\n\t`UNIQUE constraint failed: ${escapeRegExp(MIGRATION_TABLE)}\\\\.name`,\n\t\"i\",\n);\n\n/**\n * How long to wait for a concurrent migrator to finish before giving up.\n * Exported because the db init lock's reclaim deadline must comfortably\n * exceed it (see DB_INIT_DEADLINE_MS in emdash-runtime.ts) — a healthy\n * init can legitimately block this long inside waitForConcurrentMigrator.\n */\nexport const MIGRATION_RACE_WAIT_MS = 10_000;\n/** Polling interval while waiting for a concurrent migrator. */\nconst MIGRATION_RACE_POLL_MS = 100;\n\n/**\n * Pattern used to detect \"table does not exist\" errors across the dialects\n * EmDash supports. The phrasing differs by driver:\n *\n * - SQLite: `no such table: _emdash_migrations`\n * - D1: `D1_ERROR: no such table: _emdash_migrations: SQLITE_ERROR`\n * - PostgreSQL: `relation \"_emdash_migrations\" does not exist`\n * (also occasionally `table \"_emdash_migrations\" does not exist`)\n *\n * We deliberately match on the migration table name (rather than using the\n * generic `isMissingTableError` helper) so an unexpected missing-table error\n * naming a different table — implausible today since\n * `getAppliedMigrationCount` only references `MIGRATION_TABLE`, but cheap\n * insurance against future edits — is not silently swallowed. The pattern is\n * built from `MIGRATION_TABLE` so a rename cannot drift.\n */\nconst MIGRATION_TABLE_MISSING_PATTERN = new RegExp(\n\t`(?:no such table:\\\\s*(?:[a-z][a-z0-9_]*\\\\.)?${escapeRegExp(MIGRATION_TABLE)}\\\\b` +\n\t\t`|(?:relation|table)\\\\s+\"?(?:[a-z][a-z0-9_]*\\\\.)?${escapeRegExp(MIGRATION_TABLE)}\"?\\\\s+does(?:n't| not) exist\\\\b)`,\n\t\"i\",\n);\n\n/**\n * Read the count of applied migrations.\n *\n * Returns `null` only when the migration table does not exist yet (which is\n * the normal state on a fresh database before the first migration runs).\n * Any other error is rethrown so callers — particularly\n * `waitForConcurrentMigrator` — don't silently mask connection failures,\n * permission errors, or other unexpected driver problems behind a 10s wait\n * and a bogus \"we're done\" verdict.\n */\nasync function getAppliedMigrationCount(db: Kysely<Database>): Promise<number | null> {\n\ttry {\n\t\tconst result = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(MIGRATION_TABLE)}\n\t\t`.execute(db);\n\t\treturn Number(result.rows[0]?.count ?? 0);\n\t} catch (error) {\n\t\tif (MIGRATION_TABLE_MISSING_PATTERN.test(deepErrorMessage(error))) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Wait for a concurrent migrator to finish applying all migrations.\n *\n * Resolves to `true` once the migration table contains at least\n * `MIGRATION_COUNT` rows (i.e. every migration this build knows about has\n * been recorded), `false` if the deadline elapses first. We use `>=` rather\n * than `===` so that an old isolate observing a database that has already\n * been migrated by a newer build still treats the wait as settled instead\n * of timing out.\n */\nasync function waitForConcurrentMigrator(\n\tdb: Kysely<Database>,\n\twaitMs: number = MIGRATION_RACE_WAIT_MS,\n): Promise<boolean> {\n\tconst deadline = Date.now() + waitMs;\n\twhile (Date.now() < deadline) {\n\t\tconst count = await getAppliedMigrationCount(db);\n\t\tif (count !== null && count >= MIGRATION_COUNT) {\n\t\t\treturn true;\n\t\t}\n\t\tawait new Promise((resolve) => setTimeout(resolve, MIGRATION_RACE_POLL_MS));\n\t}\n\tconst finalCount = await getAppliedMigrationCount(db);\n\treturn finalCount !== null && finalCount >= MIGRATION_COUNT;\n}\n\n/** Extract the deepest error message available from a thrown value. */\nfunction deepErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst own = error.message ?? \"\";\n\t\tif (error.cause) {\n\t\t\tconst causeMsg = deepErrorMessage(error.cause);\n\t\t\treturn own ? `${own}: ${causeMsg}` : causeMsg;\n\t\t}\n\t\treturn own;\n\t}\n\tif (typeof error === \"string\") return error;\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n\n/**\n * Read exact migration status without invoking Kysely's migration\n * introspection. Registered names retain execution order; unknown database\n * records are sorted so reports remain stable across dialects.\n */\nexport async function getExactMigrationStatus(\n\tdb: Kysely<Database>,\n\toptions?: MigrationOptions,\n): Promise<ExactMigrationStatus> {\n\tconst table = options?.migrationTableSchema\n\t\t? sql`${sql.ref(options.migrationTableSchema)}.${sql.ref(MIGRATION_TABLE)}`\n\t\t: sql.ref(MIGRATION_TABLE);\n\n\tlet rows: readonly { name: string }[];\n\ttry {\n\t\tconst result = await sql<{ name: string }>`SELECT name FROM ${table}`.execute(db);\n\t\trows = result.rows;\n\t} catch (error) {\n\t\tif (MIGRATION_TABLE_MISSING_PATTERN.test(deepErrorMessage(error))) {\n\t\t\treturn {\n\t\t\t\tknownApplied: [],\n\t\t\t\tpending: [...MIGRATION_NAMES],\n\t\t\t\tunknownApplied: [],\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\n\tconst appliedNames = new Set(rows.map((row) => row.name));\n\tconst knownApplied = MIGRATION_NAMES.filter((name) => appliedNames.has(name));\n\tconst pending = MIGRATION_NAMES.filter((name) => !appliedNames.has(name));\n\tconst knownNames = new Set(MIGRATION_NAMES);\n\tconst unknownApplied = [...appliedNames].filter((name) => !knownNames.has(name)).toSorted();\n\n\treturn { knownApplied, pending, unknownApplied };\n}\n\n/**\n * Run all pending migrations.\n *\n * Includes a fast-path: if the migration table already exists and contains\n * at least MIGRATION_COUNT rows, all migrations this build knows about have\n * been applied and we can skip the Kysely Migrator entirely. This avoids\n * the expensive `pragma_table_info` introspection that Kysely runs for\n * every table in the database (twice!) just to check if the migration\n * tables exist. On D1 with ~57 tables, that's ~116 queries saved per init.\n *\n * Concurrent-migration safety: the Kysely Migrator's `acquireMigrationLock`\n * is a no-op for SQLite (and therefore D1), so two callers running this\n * concurrently against the same database will both try to apply pending\n * migrations. SQLite serializes the writes, but the loser still surfaces a\n * `UNIQUE constraint failed: _emdash_migrations.name` error. We treat that\n * specific error as benign: another caller is already applying the same\n * schema. We wait for the concurrent migrator to finish, then return\n * success. This matches the user-observable expectation that running\n * migrations twice in a row is a no-op.\n */\nexport async function runMigrations(\n\tdb: Kysely<Database>,\n\toptions?: MigrationOptions,\n): Promise<{ applied: string[] }> {\n\t// Fast path: check if all migrations are already applied.\n\t// A single cheap query vs the Migrator's full schema introspection.\n\t// We use `>=` rather than `===` so a database with extra rows from a\n\t// newer build (e.g. mid-deploy old isolate, or downgrade) still skips\n\t// the migrator instead of falling through to the race-recovery path\n\t// unnecessarily.\n\tif (!options?.migrationTableSchema) {\n\t\tconst initialCount = await getAppliedMigrationCount(db);\n\t\tif (initialCount !== null && initialCount >= MIGRATION_COUNT) {\n\t\t\treturn { applied: [] };\n\t\t}\n\t}\n\n\tconst migrator = createMigrator(db, options);\n\n\tconst { error, results } = await migrator.migrateToLatest();\n\n\tconst applied = results?.filter((r) => r.status === \"Success\").map((r) => r.migrationName) ?? [];\n\n\tif (error) {\n\t\t// Walk error.cause to get the underlying driver message — Kysely\n\t\t// often wraps with an empty top-level message.\n\t\tconst msg = deepErrorMessage(error);\n\t\tconst failedMigration = results?.find((r) => r.status === \"Error\");\n\n\t\t// Concurrent-migration race: another caller is applying (or just\n\t\t// applied) the same migration. SQLite/D1 surface it as the\n\t\t// bookkeeping UNIQUE violation (their migration lock is a no-op);\n\t\t// Postgres surfaces it as the fail-fast advisory try-lock reporting\n\t\t// busy (see pg-migration-lock.ts). Either way: wait for the\n\t\t// concurrent migrator to finish, then verify the schema is fully\n\t\t// migrated and treat as success.\n\t\tconst lockBusy = msg.includes(MIGRATION_LOCK_BUSY_MESSAGE);\n\t\tif (MIGRATION_RACE_PATTERN.test(msg) || lockBusy) {\n\t\t\tconst settled = await waitForConcurrentMigrator(db, options?.raceWaitMs);\n\t\t\tif (settled) {\n\t\t\t\treturn { applied };\n\t\t\t}\n\t\t\tif (lockBusy) {\n\t\t\t\t// The lock holder didn't finish within the wait window —\n\t\t\t\t// either it's slow or its migration is failing. Surface a\n\t\t\t\t// distinct error type instead of the raw sentinel message so\n\t\t\t\t// callers can tell \"still in progress\" from \"failed\".\n\t\t\t\tthrow new ConcurrentMigrationTimeoutError(options?.raceWaitMs ?? MIGRATION_RACE_WAIT_MS);\n\t\t\t}\n\t\t}\n\n\t\tconst failedSuffix = failedMigration ? ` (migration: ${failedMigration.migrationName})` : \"\";\n\t\tthrow new Error(`Migration failed: ${msg || \"unknown error\"}${failedSuffix}`);\n\t}\n\n\treturn { applied };\n}\n\n/**\n * Rollback the last migration\n */\nexport async function rollbackMigration(\n\tdb: Kysely<Database>,\n\toptions?: MigrationOptions,\n): Promise<{ rolledBack: string | null }> {\n\tconst migrator = createMigrator(db, options);\n\n\tconst { error, results } = await migrator.migrateDown();\n\n\tconst rolledBack = results?.[0]?.status === \"Success\" ? results[0].migrationName : null;\n\n\tif (error) {\n\t\tconst msg = error instanceof Error ? error.message : JSON.stringify(error);\n\t\tthrow new Error(`Rollback failed: ${msg}`);\n\t}\n\n\treturn { rolledBack };\n}\n"],"mappings":"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"}
|