emdash 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-34EN2eXO.d.mts → adapters-Bb1vG41D.d.mts} +8 -1
- package/dist/adapters-Bb1vG41D.d.mts.map +1 -0
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +9 -9
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +1 -1
- package/dist/{api-DdAsirBe.mjs → api-BeBglVxU.mjs} +10 -10
- package/dist/{api-DdAsirBe.mjs.map → api-BeBglVxU.mjs.map} +1 -1
- package/dist/{api-tokens-CFXu8F_2.mjs → api-tokens-KO24G1Fd.mjs} +2 -2
- package/dist/{api-tokens-CFXu8F_2.mjs.map → api-tokens-KO24G1Fd.mjs.map} +1 -1
- package/dist/{apply-D5zfeD09.mjs → apply-kUDt80-G.mjs} +16 -16
- package/dist/{apply-D5zfeD09.mjs.map → apply-kUDt80-G.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 +71 -15
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +4 -4
- package/dist/astro/middleware/redirect.mjs +2 -2
- package/dist/astro/middleware/request-context.mjs +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +10 -10
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +143 -74
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +2 -2
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +2 -2
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +3 -3
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +7 -7
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +7 -7
- package/dist/astro/routes/api/admin/bylines/index.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/_id_.mjs +2 -2
- package/dist/astro/routes/api/admin/comments/bulk.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/counts.mjs +2 -2
- package/dist/astro/routes/api/admin/comments/index.mjs +3 -3
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +1 -1
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +7 -7
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +7 -7
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +4 -4
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +7 -7
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +7 -7
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/index.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +29 -29
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +28 -28
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +29 -29
- package/dist/astro/routes/api/admin/plugins/updates.mjs +28 -28
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +28 -28
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +28 -28
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +1 -1
- package/dist/astro/routes/api/admin/users/index.mjs +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.mjs +2 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/index.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/register-options.mjs +3 -3
- package/dist/astro/routes/api/auth/logout.mjs +1 -1
- package/dist/astro/routes/api/auth/magic-link/send.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +1 -1
- package/dist/astro/routes/api/auth/me.mjs +2 -2
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/signup/complete.mjs +3 -3
- package/dist/astro/routes/api/auth/signup/request.mjs +3 -3
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +5 -5
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/authors.mjs +1 -1
- package/dist/astro/routes/api/content/_collection_/index.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/trash.mjs +2 -2
- package/dist/astro/routes/api/dashboard.mjs +4 -4
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +1 -1
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +7 -7
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +11 -11
- package/dist/astro/routes/api/manifest.mjs +2 -2
- package/dist/astro/routes/api/mcp.mjs +38 -38
- package/dist/astro/routes/api/media/_id_/confirm.mjs +2 -2
- package/dist/astro/routes/api/media/_id_/upload.mjs +2 -2
- package/dist/astro/routes/api/media/_id_/usage.mjs +6 -6
- package/dist/astro/routes/api/media/_id_.mjs +5 -5
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +1 -1
- package/dist/astro/routes/api/media/providers/index.mjs +1 -1
- package/dist/astro/routes/api/media/upload-url.mjs +3 -3
- package/dist/astro/routes/api/media.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +3 -3
- package/dist/astro/routes/api/menus/_name_/items.mjs +3 -3
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +3 -3
- package/dist/astro/routes/api/menus/_name_/translations.mjs +3 -3
- package/dist/astro/routes/api/menus/_name_.mjs +3 -3
- package/dist/astro/routes/api/menus/index.mjs +3 -3
- package/dist/astro/routes/api/oauth/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
- package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
- package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
- package/dist/astro/routes/api/oauth/register.mjs +1 -1
- package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
- package/dist/astro/routes/api/oauth/token.mjs +4 -4
- package/dist/astro/routes/api/openapi.json.mjs +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
- package/dist/astro/routes/api/redirects/404s/index.mjs +3 -3
- package/dist/astro/routes/api/redirects/404s/summary.mjs +3 -3
- package/dist/astro/routes/api/redirects/_id_.mjs +4 -4
- package/dist/astro/routes/api/redirects/index.mjs +4 -4
- package/dist/astro/routes/api/relations/_id_/index.mjs +9 -9
- package/dist/astro/routes/api/relations/_id_/translations.mjs +8 -8
- package/dist/astro/routes/api/relations/index.mjs +9 -9
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +28 -28
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +28 -28
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +28 -28
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +28 -28
- package/dist/astro/routes/api/schema/collections/index.mjs +28 -28
- package/dist/astro/routes/api/schema/collections/reorder.mjs +28 -28
- package/dist/astro/routes/api/schema/index.mjs +6 -6
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +28 -28
- package/dist/astro/routes/api/schema/orphans/index.mjs +28 -28
- package/dist/astro/routes/api/search/enable.mjs +5 -5
- package/dist/astro/routes/api/search/index.mjs +4 -4
- package/dist/astro/routes/api/search/rebuild.mjs +5 -5
- package/dist/astro/routes/api/search/stats.mjs +4 -4
- package/dist/astro/routes/api/search/suggest.mjs +4 -4
- package/dist/astro/routes/api/sections/_slug_.mjs +4 -4
- package/dist/astro/routes/api/sections/index.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +3 -3
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +3 -3
- package/dist/astro/routes/api/settings/backups/export.mjs +3 -3
- package/dist/astro/routes/api/settings/backups/index.mjs +3 -3
- package/dist/astro/routes/api/settings/email.mjs +1 -1
- package/dist/astro/routes/api/settings.mjs +5 -5
- package/dist/astro/routes/api/setup/admin-verify.mjs +4 -4
- package/dist/astro/routes/api/setup/admin.mjs +4 -4
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +18 -21
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/index.mjs +15 -21
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +2 -2
- package/dist/astro/routes/api/snapshot.mjs +4 -4
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/index.mjs +6 -6
- package/dist/astro/routes/api/themes/preview.mjs +2 -2
- package/dist/astro/routes/api/typegen.mjs +3 -3
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +4 -4
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +4 -4
- package/dist/astro/routes/api/widget-areas/_name_.mjs +3 -3
- package/dist/astro/routes/api/widget-areas/index.mjs +4 -4
- package/dist/astro/routes/robots.txt.mjs +2 -2
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +2 -2
- package/dist/astro/routes/sitemap.xml.mjs +2 -2
- package/dist/astro/types.d.mts +14 -14
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-1iFJzPaZ.mjs → authorize-DUElxgOQ.mjs} +1 -1
- package/dist/{authorize-1iFJzPaZ.mjs.map → authorize-DUElxgOQ.mjs.map} +1 -1
- package/dist/{backup-LHjIAVNP.mjs → backup-DWYpJlLj.mjs} +3 -3
- package/dist/{backup-LHjIAVNP.mjs.map → backup-DWYpJlLj.mjs.map} +1 -1
- package/dist/{bundle-CBEXrBnb.mjs → bundle-vn56sLos.mjs} +5 -5
- package/dist/{bundle-CBEXrBnb.mjs.map → bundle-vn56sLos.mjs.map} +1 -1
- package/dist/{byline-fields-C5S8wygO.mjs → byline-fields-txaLGoME.mjs} +1 -1
- package/dist/{byline-fields-C5S8wygO.mjs.map → byline-fields-txaLGoME.mjs.map} +1 -1
- package/dist/{byline-pEcoDps8.mjs → byline-yjvWq4ip.mjs} +4 -4
- package/dist/{byline-pEcoDps8.mjs.map → byline-yjvWq4ip.mjs.map} +1 -1
- package/dist/{bylines-DJfSfXCL.mjs → bylines-Bu7pchQ4.mjs} +3 -3
- package/dist/{bylines-DJfSfXCL.mjs.map → bylines-Bu7pchQ4.mjs.map} +1 -1
- package/dist/{bylines-BWemdX2k.mjs → bylines-DjXS5p0P.mjs} +5 -5
- package/dist/{bylines-BWemdX2k.mjs.map → bylines-DjXS5p0P.mjs.map} +1 -1
- package/dist/{cache-CBJaDy_E.mjs → cache-C46-3Irl.mjs} +2 -2
- package/dist/{cache-CBJaDy_E.mjs.map → cache-C46-3Irl.mjs.map} +1 -1
- package/dist/{challenge-store-CZyFVaad.mjs → challenge-store-SIL5DsF2.mjs} +1 -1
- package/dist/{challenge-store-CZyFVaad.mjs.map → challenge-store-SIL5DsF2.mjs.map} +1 -1
- package/dist/{chunks-DfPax1I0.mjs → chunks-fiZ8G9RJ.mjs} +2 -2
- package/dist/{chunks-DfPax1I0.mjs.map → chunks-fiZ8G9RJ.mjs.map} +1 -1
- package/dist/cli/index.mjs +551 -51
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.mjs +2 -2
- package/dist/{collection-deletion-C8BugSGz.mjs → collection-deletion-DQPvMD8R.mjs} +2 -2
- package/dist/{collection-deletion-C8BugSGz.mjs.map → collection-deletion-DQPvMD8R.mjs.map} +1 -1
- package/dist/{comment-reaction-D6qfHKBc.mjs → comment-reaction-D-2J84UE.mjs} +2 -2
- package/dist/{comment-reaction-D6qfHKBc.mjs.map → comment-reaction-D-2J84UE.mjs.map} +1 -1
- package/dist/{comments-CTOuhTSX.mjs → comments-CTfZtLmM.mjs} +1 -1
- package/dist/{comments-CTOuhTSX.mjs.map → comments-CTfZtLmM.mjs.map} +1 -1
- package/dist/config-COQzTe5Q.d.mts +34 -0
- package/dist/config-COQzTe5Q.d.mts.map +1 -0
- package/dist/{content-BNfwh7xX.mjs → content-ZHCc1ngN.mjs} +3 -3
- package/dist/{content-BNfwh7xX.mjs.map → content-ZHCc1ngN.mjs.map} +1 -1
- package/dist/{content-list-query-DhQ84eVV.d.mts → content-list-query-wJ2WN8Vp.d.mts} +1 -1
- package/dist/{content-list-query-DhQ84eVV.d.mts.map → content-list-query-wJ2WN8Vp.d.mts.map} +1 -1
- package/dist/{content-refresh-DNERP4-f.mjs → content-refresh-B_8SJzuU.mjs} +2 -2
- package/dist/{content-refresh-DNERP4-f.mjs.map → content-refresh-B_8SJzuU.mjs.map} +1 -1
- package/dist/{context-DRgOvSnW.mjs → context-ZldbZcle.mjs} +7 -7
- package/dist/{context-DRgOvSnW.mjs.map → context-ZldbZcle.mjs.map} +1 -1
- package/dist/{dashboard-CB8J89rJ.mjs → dashboard-DvHbk_cv.mjs} +3 -3
- package/dist/{dashboard-CB8J89rJ.mjs.map → dashboard-DvHbk_cv.mjs.map} +1 -1
- package/dist/db/index.d.mts +4 -4
- package/dist/db/index.mjs +30 -7
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +11 -0
- package/dist/db/libsql-migrations.d.mts.map +1 -0
- package/dist/db/libsql-migrations.mjs +57 -0
- package/dist/db/libsql-migrations.mjs.map +1 -0
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +10 -0
- package/dist/db/postgres-migrations.d.mts.map +1 -0
- package/dist/db/postgres-migrations.mjs +47 -0
- package/dist/db/postgres-migrations.mjs.map +1 -0
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +10 -0
- package/dist/db/sqlite-migrations.d.mts.map +1 -0
- package/dist/db/sqlite-migrations.mjs +28 -0
- package/dist/db/sqlite-migrations.mjs.map +1 -0
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{deferred-tasks-BMsa9F64.d.mts → deferred-tasks-SDWxrgzJ.d.mts} +1 -1
- package/dist/{deferred-tasks-BMsa9F64.d.mts.map → deferred-tasks-SDWxrgzJ.d.mts.map} +1 -1
- package/dist/{device-flow-CaioYGK3.mjs → device-flow-C0GdD_z8.mjs} +4 -4
- package/dist/{device-flow-CaioYGK3.mjs.map → device-flow-C0GdD_z8.mjs.map} +1 -1
- package/dist/direct-executor-CDXeJCSs.mjs +85 -0
- package/dist/direct-executor-CDXeJCSs.mjs.map +1 -0
- package/dist/{escape-C_aLKP3H.mjs → escape-DUY2r2Zs.mjs} +1 -1
- package/dist/{escape-C_aLKP3H.mjs.map → escape-DUY2r2Zs.mjs.map} +1 -1
- package/dist/{field-defs-cache-hg6QkjV9.mjs → field-defs-cache-BzwBlJrR.mjs} +2 -2
- package/dist/{field-defs-cache-hg6QkjV9.mjs.map → field-defs-cache-BzwBlJrR.mjs.map} +1 -1
- package/dist/{fts-manager-CZ-5dVwJ.mjs → fts-manager-DyZEohZC.mjs} +2 -2
- package/dist/{fts-manager-CZ-5dVwJ.mjs.map → fts-manager-DyZEohZC.mjs.map} +1 -1
- package/dist/{hreflang-DNswoYsi.mjs → hreflang-BBe83kKa.mjs} +5 -5
- package/dist/{hreflang-DNswoYsi.mjs.map → hreflang-BBe83kKa.mjs.map} +1 -1
- package/dist/{hreflang-D3Uehfv2.d.mts → hreflang-DwT2E0Sa.d.mts} +2 -2
- package/dist/{hreflang-D3Uehfv2.d.mts.map → hreflang-DwT2E0Sa.d.mts.map} +1 -1
- package/dist/identity-Ys6Dlc9C.mjs +35 -0
- package/dist/identity-Ys6Dlc9C.mjs.map +1 -0
- package/dist/{import-B41u8Rot.mjs → import-DPkLmeXO.mjs} +2 -2
- package/dist/{import-B41u8Rot.mjs.map → import-DPkLmeXO.mjs.map} +1 -1
- package/dist/{index-C3Y-rsyN.d.mts → index-BVBZj4-7.d.mts} +28 -49
- package/dist/index-BVBZj4-7.d.mts.map +1 -0
- package/dist/{index-Cof4-Fab.d.mts → index-C9KuQyO-.d.mts} +3 -3
- package/dist/{index-Cof4-Fab.d.mts.map → index-C9KuQyO-.d.mts.map} +1 -1
- package/dist/index.d.mts +21 -20
- package/dist/index.mjs +42 -42
- package/dist/{load-DmvJrtxS.mjs → load-YJ2xl3ra.mjs} +2 -2
- package/dist/{load-DmvJrtxS.mjs.map → load-YJ2xl3ra.mjs.map} +1 -1
- package/dist/{loader-DLBqRiGP.mjs → loader-CdG_Ci3H.mjs} +2 -2
- package/dist/{loader-DLBqRiGP.mjs.map → loader-CdG_Ci3H.mjs.map} +1 -1
- package/dist/manifest-builder-B252yQUf.mjs +189 -0
- package/dist/manifest-builder-B252yQUf.mjs.map +1 -0
- package/dist/media/index.d.mts +1 -1
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +2 -2
- package/dist/{media-allowlist-BD6HhgXA.mjs → media-allowlist-D6x-Us02.mjs} +1 -1
- package/dist/{media-allowlist-BD6HhgXA.mjs.map → media-allowlist-D6x-Us02.mjs.map} +1 -1
- package/dist/{media-upload-9yas9zGH.mjs → media-upload-CHBVn6m-.mjs} +2 -2
- package/dist/{media-upload-9yas9zGH.mjs.map → media-upload-CHBVn6m-.mjs.map} +1 -1
- package/dist/{media-usage-De3qvwjc.mjs → media-usage-BZCydfvu.mjs} +4 -4
- package/dist/{media-usage-De3qvwjc.mjs.map → media-usage-BZCydfvu.mjs.map} +1 -1
- package/dist/{media-usage-work-B9Bksh_b.mjs → media-usage-work-CLo_6tct.mjs} +2 -2
- package/dist/{media-usage-work-B9Bksh_b.mjs.map → media-usage-work-CLo_6tct.mjs.map} +1 -1
- package/dist/{menus-CC-yn1F9.mjs → menus-DSo5QeW0.mjs} +6 -6
- package/dist/{menus-CC-yn1F9.mjs.map → menus-DSo5QeW0.mjs.map} +1 -1
- package/dist/{menus-fxvEDYE6.mjs → menus-TCNSd2vp.mjs} +2 -2
- package/dist/{menus-fxvEDYE6.mjs.map → menus-TCNSd2vp.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +22 -0
- package/dist/migrations/index.d.mts.map +1 -0
- package/dist/migrations/index.mjs +7 -0
- package/dist/{mode-Bpe-tNNy.mjs → mode-BDoH_WcF.mjs} +1 -1
- package/dist/{mode-Bpe-tNNy.mjs.map → mode-BDoH_WcF.mjs.map} +1 -1
- package/dist/{oauth-authorization-BXO1MKej.mjs → oauth-authorization-iOikmrJd.mjs} +4 -4
- package/dist/{oauth-authorization-BXO1MKej.mjs.map → oauth-authorization-iOikmrJd.mjs.map} +1 -1
- package/dist/{oauth-clients-C_DNqtRu.mjs → oauth-clients-CvI0nHMJ.mjs} +1 -1
- package/dist/{oauth-clients-C_DNqtRu.mjs.map → oauth-clients-CvI0nHMJ.mjs.map} +1 -1
- package/dist/{oauth-state-store-DwAxMtk4.mjs → oauth-state-store-Ba8KZlwW.mjs} +1 -1
- package/dist/{oauth-state-store-DwAxMtk4.mjs.map → oauth-state-store-Ba8KZlwW.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-BxfZizdk.mjs → oauth-user-lookup-C5SQwGYC.mjs} +1 -1
- package/dist/{oauth-user-lookup-BxfZizdk.mjs.map → oauth-user-lookup-C5SQwGYC.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-DRe1pIBL.d.mts → options--hhz-jZ1.d.mts} +3 -3
- package/dist/{options-DRe1pIBL.d.mts.map → options--hhz-jZ1.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{passkey-config-_2GOwwK8.mjs → passkey-config-DFAmUyuE.mjs} +1 -1
- package/dist/{passkey-config-_2GOwwK8.mjs.map → passkey-config-DFAmUyuE.mjs.map} +1 -1
- package/dist/{placeholder-CzW7Lshs.d.mts → placeholder-Dp0K3RkD.d.mts} +1 -1
- package/dist/{placeholder-CzW7Lshs.d.mts.map → placeholder-Dp0K3RkD.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/policy-TluUIxuu.mjs +45 -0
- package/dist/policy-TluUIxuu.mjs.map +1 -0
- package/dist/{portable-text-DhKbDAGr.mjs → portable-text-imBW5cHK.mjs} +1 -1
- package/dist/{portable-text-DhKbDAGr.mjs.map → portable-text-imBW5cHK.mjs.map} +1 -1
- package/dist/protocol-DjsJHTlK.d.mts +52 -0
- package/dist/protocol-DjsJHTlK.d.mts.map +1 -0
- package/dist/{query-vgZNwIhh.mjs → query-BWs7O5Il.mjs} +3 -3
- package/dist/{query-vgZNwIhh.mjs.map → query-BWs7O5Il.mjs.map} +1 -1
- package/dist/{query-BgjfiLUQ.mjs → query-zTVAR1Sl.mjs} +12 -12
- package/dist/{query-BgjfiLUQ.mjs.map → query-zTVAR1Sl.mjs.map} +1 -1
- package/dist/{rate-limit-L5anykgo.mjs → rate-limit-Bx4g9m3p.mjs} +1 -1
- package/dist/{rate-limit-L5anykgo.mjs.map → rate-limit-Bx4g9m3p.mjs.map} +1 -1
- package/dist/{redirect-KBNE3UEs.mjs → redirect-BgAOGHDq.mjs} +1 -1
- package/dist/{redirect-KBNE3UEs.mjs.map → redirect-BgAOGHDq.mjs.map} +1 -1
- package/dist/{redirects-cV9g7V-0.mjs → redirects-DTDHWH31.mjs} +2 -2
- package/dist/{redirects-cV9g7V-0.mjs.map → redirects-DTDHWH31.mjs.map} +1 -1
- package/dist/{redirects-CufRQt0Q.mjs → redirects-DyChwDkG.mjs} +1 -1
- package/dist/{redirects-CufRQt0Q.mjs.map → redirects-DyChwDkG.mjs.map} +1 -1
- package/dist/{registry-C581V4TP.mjs → registry-Cqa2I749.mjs} +6 -6
- package/dist/{registry-C581V4TP.mjs.map → registry-Cqa2I749.mjs.map} +1 -1
- package/dist/{relation-DtmAQH7s.mjs → relation-BnHB0T4J.mjs} +2 -2
- package/dist/{relation-DtmAQH7s.mjs.map → relation-BnHB0T4J.mjs.map} +1 -1
- package/dist/{relations-DItI3MN9.d.mts → relations-BHo5A8Zf.d.mts} +35 -35
- package/dist/{relations-DItI3MN9.d.mts.map → relations-BHo5A8Zf.d.mts.map} +1 -1
- package/dist/{relations-DICSyfsh.mjs → relations-D5sM5fW0.mjs} +4 -4
- package/dist/{relations-DICSyfsh.mjs.map → relations-D5sM5fW0.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{runner-CgQbELYC.d.mts → runner-BYHZn3Jy.d.mts} +16 -3
- package/dist/runner-BYHZn3Jy.d.mts.map +1 -0
- package/dist/{runner-BiDvq5dv.mjs → runner-C1T11CfC.mjs} +34 -4
- package/dist/{runner-BiDvq5dv.mjs.map → runner-C1T11CfC.mjs.map} +1 -1
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-CeQSNwB3.mjs → schema-2AOsSn2v.mjs} +4 -4
- package/dist/{schema-CeQSNwB3.mjs.map → schema-2AOsSn2v.mjs.map} +1 -1
- package/dist/{schema-BFyTg38T.mjs → schema-DZ5YVVZj.mjs} +3 -3
- package/dist/{schema-BFyTg38T.mjs.map → schema-DZ5YVVZj.mjs.map} +1 -1
- package/dist/{scopes-BVeuhGBE.mjs → scopes-8ClPF2bC.mjs} +2 -2
- package/dist/{scopes-BVeuhGBE.mjs.map → scopes-8ClPF2bC.mjs.map} +1 -1
- package/dist/{search-BpuPKZb0.mjs → search-u1QYdOCG.mjs} +4 -4
- package/dist/{search-BpuPKZb0.mjs.map → search-u1QYdOCG.mjs.map} +1 -1
- package/dist/{secrets-dtYs2hDo.mjs → secrets-BEgsAQEU.mjs} +1 -1
- package/dist/{secrets-dtYs2hDo.mjs.map → secrets-BEgsAQEU.mjs.map} +1 -1
- package/dist/{sections-COctk6hf.mjs → sections-DmHviGyM.mjs} +2 -2
- package/dist/{sections-COctk6hf.mjs.map → sections-DmHviGyM.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +13 -13
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +9 -9
- package/dist/{seo-CvDxfvFb.mjs → seo-Dq4G-RrO.mjs} +2 -2
- package/dist/{seo-CvDxfvFb.mjs.map → seo-Dq4G-RrO.mjs.map} +1 -1
- package/dist/{service-xMiMSTsR.mjs → service-BpArayPr.mjs} +2 -2
- package/dist/{service-xMiMSTsR.mjs.map → service-BpArayPr.mjs.map} +1 -1
- package/dist/{session-user-BzVemLkw.mjs → session-user-BEorKVT-.mjs} +1 -1
- package/dist/{session-user-BzVemLkw.mjs.map → session-user-BEorKVT-.mjs.map} +1 -1
- package/dist/{settings-BE9aqn_9.mjs → settings-DE9xtzqd.mjs} +3 -3
- package/dist/{settings-BE9aqn_9.mjs.map → settings-DE9xtzqd.mjs.map} +1 -1
- package/dist/{settings-B372MV0p.mjs → settings-xRdoUZr0.mjs} +2 -2
- package/dist/{settings-B372MV0p.mjs.map → settings-xRdoUZr0.mjs.map} +1 -1
- package/dist/{setup-complete-DF7TAfD5.mjs → setup-complete-BnT8pq_C.mjs} +1 -1
- package/dist/{setup-complete-DF7TAfD5.mjs.map → setup-complete-BnT8pq_C.mjs.map} +1 -1
- package/dist/{setup-nonce-Do-U_cg9.mjs → setup-nonce-CBitf_oQ.mjs} +1 -1
- package/dist/{setup-nonce-Do-U_cg9.mjs.map → setup-nonce-CBitf_oQ.mjs.map} +1 -1
- package/dist/{site-url-Bowsi9T-.mjs → site-url-DjpIXMXJ.mjs} +1 -1
- package/dist/{site-url-Bowsi9T-.mjs.map → site-url-DjpIXMXJ.mjs.map} +1 -1
- package/dist/{snapshot-B5h6aPMh.mjs → snapshot-BBlGkb2q.mjs} +1 -1
- package/dist/{snapshot-B5h6aPMh.mjs.map → snapshot-BBlGkb2q.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +2 -2
- package/dist/storage/s3.d.mts +1 -1
- package/dist/target-DixqqV5i.mjs +27 -0
- package/dist/target-DixqqV5i.mjs.map +1 -0
- package/dist/{taxonomies-B0o9ExNV.mjs → taxonomies-BlrncHi9.mjs} +5 -5
- package/dist/{taxonomies-B0o9ExNV.mjs.map → taxonomies-BlrncHi9.mjs.map} +1 -1
- package/dist/{taxonomies-Dk3MAklL.mjs → taxonomies-OHUIiIpI.mjs} +4 -4
- package/dist/{taxonomies-Dk3MAklL.mjs.map → taxonomies-OHUIiIpI.mjs.map} +1 -1
- package/dist/{taxonomy-CPeM8d2o.mjs → taxonomy-BqCZ1TdU.mjs} +3 -3
- package/dist/{taxonomy-CPeM8d2o.mjs.map → taxonomy-BqCZ1TdU.mjs.map} +1 -1
- package/dist/{transport--CfOflrp.mjs → transport-DBJwa-Si.mjs} +1 -1
- package/dist/{transport--CfOflrp.mjs.map → transport-DBJwa-Si.mjs.map} +1 -1
- package/dist/{transport-B_rfeU-a.d.mts → transport-RQE36APG.d.mts} +1 -1
- package/dist/{transport-B_rfeU-a.d.mts.map → transport-RQE36APG.d.mts.map} +1 -1
- package/dist/{types-CFUfyt1s.d.mts → types-BcqdcT-r.d.mts} +1 -1
- package/dist/{types-CFUfyt1s.d.mts.map → types-BcqdcT-r.d.mts.map} +1 -1
- package/dist/{types-CPx2lIGo.d.mts → types-BntycPTF.d.mts} +1 -1
- package/dist/{types-CPx2lIGo.d.mts.map → types-BntycPTF.d.mts.map} +1 -1
- package/dist/{types-C3_AbkDP.d.mts → types-C2pMvO62.d.mts} +1 -1
- package/dist/{types-C3_AbkDP.d.mts.map → types-C2pMvO62.d.mts.map} +1 -1
- package/dist/{types-DefV3OiO.d.mts → types-CXnOzDe1.d.mts} +1 -1
- package/dist/{types-DefV3OiO.d.mts.map → types-CXnOzDe1.d.mts.map} +1 -1
- package/dist/{types-D4_1Ga4L.d.mts → types-DN64_zzZ.d.mts} +3 -3
- package/dist/{types-D4_1Ga4L.d.mts.map → types-DN64_zzZ.d.mts.map} +1 -1
- package/dist/{types-CAGdePf3.d.mts → types-DQIDRKF2.d.mts} +1 -1
- package/dist/{types-CAGdePf3.d.mts.map → types-DQIDRKF2.d.mts.map} +1 -1
- package/dist/{types-BPuloofb.d.mts → types-DWRhk9xZ.d.mts} +1 -1
- package/dist/{types-BPuloofb.d.mts.map → types-DWRhk9xZ.d.mts.map} +1 -1
- package/dist/{types-X0MThr7x.d.mts → types-Dfk8KI5R.d.mts} +1 -1
- package/dist/{types-X0MThr7x.d.mts.map → types-Dfk8KI5R.d.mts.map} +1 -1
- package/dist/{types-Cs-TFLNf.d.mts → types-DrJrVCT1.d.mts} +3 -3
- package/dist/{types-Cs-TFLNf.d.mts.map → types-DrJrVCT1.d.mts.map} +1 -1
- package/dist/{upload-attempts-hlne3iA1.mjs → upload-attempts-D4FS8LT6.mjs} +1 -1
- package/dist/{upload-attempts-hlne3iA1.mjs.map → upload-attempts-D4FS8LT6.mjs.map} +1 -1
- package/dist/{user-sHgJ62SP.mjs → user-DJZfUJVE.mjs} +2 -2
- package/dist/{user-sHgJ62SP.mjs.map → user-DJZfUJVE.mjs.map} +1 -1
- package/dist/{validate-BkqIG_Uj.mjs → validate-BMLBvxOC.mjs} +2 -2
- package/dist/{validate-BkqIG_Uj.mjs.map → validate-BMLBvxOC.mjs.map} +1 -1
- package/dist/{validate-DeGtBN84.d.mts → validate-CTqt5nuE.d.mts} +5 -5
- package/dist/{validate-DeGtBN84.d.mts.map → validate-CTqt5nuE.d.mts.map} +1 -1
- package/dist/{validation-CiJb_X5o.mjs → validation-npvENUCB.mjs} +7 -7
- package/dist/{validation-CiJb_X5o.mjs.map → validation-npvENUCB.mjs.map} +1 -1
- package/dist/version-DB_fqCSI.mjs +7 -0
- package/dist/{version-x0NjTScG.mjs.map → version-DB_fqCSI.mjs.map} +1 -1
- package/dist/{widgets-Cwzvww0W.mjs → widgets-BD3ho7Rq.mjs} +2 -2
- package/dist/{widgets-Cwzvww0W.mjs.map → widgets-BD3ho7Rq.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-QZjWxjyk.mjs → wxr-taxonomies-B1R3vBoD.mjs} +3 -3
- package/dist/{wxr-taxonomies-QZjWxjyk.mjs.map → wxr-taxonomies-B1R3vBoD.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-CmC0ZsDr.d.mts → wxr-taxonomies-Ca68766D.d.mts} +1 -1
- package/dist/{wxr-taxonomies-CmC0ZsDr.d.mts.map → wxr-taxonomies-Ca68766D.d.mts.map} +1 -1
- package/dist/{zod-generator-D11MhxG4.mjs → zod-generator-LC-on_Vb.mjs} +2 -2
- package/dist/{zod-generator-D11MhxG4.mjs.map → zod-generator-LC-on_Vb.mjs.map} +1 -1
- package/package.json +21 -5
- package/src/astro/integration/index.ts +46 -14
- package/src/astro/integration/runtime.ts +3 -0
- package/src/astro/middleware/scoped-db.ts +21 -0
- package/src/astro/middleware.ts +67 -10
- package/src/astro/routes/api/auth/dev-bypass.ts +0 -4
- package/src/astro/routes/api/setup/dev-bypass.ts +2 -7
- package/src/astro/routes/api/setup/index.ts +5 -13
- package/src/cli/commands/migrate.ts +593 -0
- package/src/cli/index.ts +2 -23
- package/src/database/index.ts +8 -2
- package/src/database/migrations/policy.ts +70 -0
- package/src/database/migrations/runner.ts +49 -3
- package/src/db/adapters.ts +50 -2
- package/src/db/index.ts +3 -1
- package/src/db/libsql-migrations.ts +72 -0
- package/src/db/postgres-migrations.ts +59 -0
- package/src/db/sqlite-migrations.ts +37 -0
- package/src/emdash-runtime.ts +44 -15
- package/src/i18n/normalize.ts +31 -0
- package/src/index.ts +7 -1
- package/src/migrations/config-loader.ts +205 -0
- package/src/migrations/direct-executor.ts +141 -0
- package/src/migrations/identity.ts +46 -0
- package/src/migrations/index.ts +19 -0
- package/src/migrations/integration-metadata.ts +67 -0
- package/src/migrations/manifest-builder.ts +55 -0
- package/src/migrations/manifest-writer.ts +63 -0
- package/src/migrations/manifest.ts +197 -0
- package/src/migrations/protocol.ts +59 -0
- package/src/migrations/target.ts +35 -0
- package/src/virtual-modules.d.ts +8 -0
- package/dist/adapters-34EN2eXO.d.mts.map +0 -1
- package/dist/index-C3Y-rsyN.d.mts.map +0 -1
- package/dist/runner-CgQbELYC.d.mts.map +0 -1
- package/dist/version-x0NjTScG.mjs +0 -7
- /package/dist/{api-tokens-CyTsLszZ.mjs → api-tokens-rIXC6LdE.mjs} +0 -0
|
@@ -13,7 +13,6 @@ import { isParseError, parseBody } from "#api/parse.js";
|
|
|
13
13
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
14
14
|
import { setupBody } from "#api/schemas.js";
|
|
15
15
|
import { getAuthMode } from "#auth/mode.js";
|
|
16
|
-
import { runMigrations } from "#db/migrations/runner.js";
|
|
17
16
|
import { OptionsRepository } from "#db/repositories/options.js";
|
|
18
17
|
import { applySeed } from "#seed/apply.js";
|
|
19
18
|
import { loadSeed } from "#seed/load.js";
|
|
@@ -45,24 +44,17 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
45
44
|
const body = await parseBody(request, setupBody);
|
|
46
45
|
if (isParseError(body)) return body;
|
|
47
46
|
|
|
48
|
-
//
|
|
49
|
-
try {
|
|
50
|
-
await runMigrations(emdash.db);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
return handleError(error, "Failed to run database migrations", "MIGRATION_ERROR");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. Load seed file (user seed or built-in default)
|
|
47
|
+
// Load seed file (user seed or built-in default)
|
|
56
48
|
const seed = await loadSeed();
|
|
57
49
|
|
|
58
|
-
//
|
|
50
|
+
// Override seed settings with form values
|
|
59
51
|
seed.settings = {
|
|
60
52
|
...seed.settings,
|
|
61
53
|
title: body.title,
|
|
62
54
|
tagline: body.tagline,
|
|
63
55
|
};
|
|
64
56
|
|
|
65
|
-
//
|
|
57
|
+
// Apply seed
|
|
66
58
|
const validation = validateSeed(seed);
|
|
67
59
|
if (!validation.valid) {
|
|
68
60
|
return apiError("INVALID_SEED", `Invalid seed file: ${validation.errors.join(", ")}`, 400);
|
|
@@ -79,7 +71,7 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
79
71
|
return handleError(error, "Failed to apply seed", "SEED_ERROR");
|
|
80
72
|
}
|
|
81
73
|
|
|
82
|
-
//
|
|
74
|
+
// Store setup state
|
|
83
75
|
// In external auth mode, mark setup complete immediately (first user to login becomes admin)
|
|
84
76
|
// Otherwise, setup_complete is set after admin user is created (passkey or auth provider)
|
|
85
77
|
const authMode = getAuthMode(emdash.config);
|
|
@@ -117,7 +109,7 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
117
109
|
// Non-fatal - continue anyway
|
|
118
110
|
}
|
|
119
111
|
|
|
120
|
-
//
|
|
112
|
+
// Return success with result
|
|
121
113
|
return apiSuccess({
|
|
122
114
|
success: true,
|
|
123
115
|
// In external auth mode, setup is complete - redirect to admin
|
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, isAbsolute, parse, resolve } from "node:path";
|
|
4
|
+
import { createInterface } from "node:readline/promises";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
|
|
9
|
+
import { buildMigrationManifestFromConfig } from "../../migrations/config-loader.js";
|
|
10
|
+
import type { CoreMigrationIdentity } from "../../migrations/identity.js";
|
|
11
|
+
import type { MigrationManifestV1 } from "../../migrations/manifest.js";
|
|
12
|
+
import {
|
|
13
|
+
MigrationManifestValidationError,
|
|
14
|
+
validateMigrationManifest,
|
|
15
|
+
} from "../../migrations/manifest.js";
|
|
16
|
+
import type {
|
|
17
|
+
MigrationExecutor,
|
|
18
|
+
MigrationExecutorFactory,
|
|
19
|
+
MigrationReport,
|
|
20
|
+
MigrationTarget,
|
|
21
|
+
MigrationTargetOverrides,
|
|
22
|
+
} from "../../migrations/protocol.js";
|
|
23
|
+
|
|
24
|
+
const FINGERPRINT_PATTERN = /^[0-9a-f]{64}$/;
|
|
25
|
+
const SAFE_TARGET_KIND_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
26
|
+
const SAFE_MIGRATION_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
|
|
27
|
+
const CREDENTIAL_URL_PATTERN = /:\/\/[^/\s]+@/;
|
|
28
|
+
const CREDENTIAL_QUERY_PATTERN = /[?&](?:auth|credential|key|password|secret|signature|token)=/i;
|
|
29
|
+
|
|
30
|
+
export const MIGRATE_EXIT_CODES = Object.freeze({
|
|
31
|
+
success: 0,
|
|
32
|
+
error: 1,
|
|
33
|
+
pending: 2,
|
|
34
|
+
unknownApplied: 3,
|
|
35
|
+
confirmation: 4,
|
|
36
|
+
interrupted: 130,
|
|
37
|
+
} as const);
|
|
38
|
+
|
|
39
|
+
export type MigrationSignal = "SIGINT" | "SIGTERM";
|
|
40
|
+
|
|
41
|
+
export interface MigrateCommandOptions extends MigrationTargetOverrides {
|
|
42
|
+
manifest?: string;
|
|
43
|
+
fromConfig?: boolean;
|
|
44
|
+
config?: string;
|
|
45
|
+
check?: boolean;
|
|
46
|
+
status?: boolean;
|
|
47
|
+
json?: boolean;
|
|
48
|
+
expectedTargetFingerprint?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface MigrateCommandDependencies {
|
|
52
|
+
cwd: string;
|
|
53
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
54
|
+
interactive: boolean;
|
|
55
|
+
findProjectRoot: (start: string) => Promise<string>;
|
|
56
|
+
readManifest: (path: string, isDefault: boolean) => Promise<unknown>;
|
|
57
|
+
buildManifestFromConfig: (projectRoot: string, configFile?: string) => Promise<unknown>;
|
|
58
|
+
loadProjectIdentity: (projectRoot: string) => Promise<CoreMigrationIdentity>;
|
|
59
|
+
loadProjectExecutor: (
|
|
60
|
+
projectRoot: string,
|
|
61
|
+
entrypoint: string,
|
|
62
|
+
) => Promise<MigrationExecutorFactory>;
|
|
63
|
+
confirm: (message: string) => Promise<boolean>;
|
|
64
|
+
writeStdout: (value: string) => void;
|
|
65
|
+
writeStderr: (value: string) => void;
|
|
66
|
+
onSignal: (signal: MigrationSignal, handler: () => Promise<void>) => () => void;
|
|
67
|
+
cleanupTimeoutMs: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class MigrateCommandError extends Error {
|
|
71
|
+
constructor(message: string) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "MigrateCommandError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isRecord(value: unknown): value is Record<PropertyKey, unknown> {
|
|
78
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function moduleExport(module: unknown, name: string): unknown {
|
|
82
|
+
if (!isRecord(module)) return undefined;
|
|
83
|
+
const direct = Reflect.get(module, name);
|
|
84
|
+
if (direct !== undefined) return direct;
|
|
85
|
+
const defaultExport = Reflect.get(module, "default");
|
|
86
|
+
return isRecord(defaultExport) ? Reflect.get(defaultExport, name) : undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function importProjectModule(projectRoot: string, specifier: string): Promise<unknown> {
|
|
90
|
+
let resolvedEntrypoint: string;
|
|
91
|
+
try {
|
|
92
|
+
resolvedEntrypoint = createRequire(resolve(projectRoot, "package.json")).resolve(specifier);
|
|
93
|
+
} catch {
|
|
94
|
+
throw new MigrateCommandError(`Could not resolve ${specifier} from the project.`);
|
|
95
|
+
}
|
|
96
|
+
return import(pathToFileURL(resolvedEntrypoint).href);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function validateIdentity(value: unknown): CoreMigrationIdentity {
|
|
100
|
+
if (
|
|
101
|
+
!isRecord(value) ||
|
|
102
|
+
typeof value.emdashVersion !== "string" ||
|
|
103
|
+
!Array.isArray(value.names) ||
|
|
104
|
+
!value.names.every((name) => typeof name === "string") ||
|
|
105
|
+
typeof value.fingerprint !== "string" ||
|
|
106
|
+
!FINGERPRINT_PATTERN.test(value.fingerprint)
|
|
107
|
+
) {
|
|
108
|
+
throw new MigrateCommandError(
|
|
109
|
+
"The project-local emdash/migrations module returned an invalid migration identity.",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
emdashVersion: value.emdashVersion,
|
|
114
|
+
names: [...value.names],
|
|
115
|
+
fingerprint: value.fingerprint,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function loadProjectMigrationIdentity(
|
|
120
|
+
projectRoot: string,
|
|
121
|
+
): Promise<CoreMigrationIdentity> {
|
|
122
|
+
const loaded = await importProjectModule(projectRoot, "emdash/migrations");
|
|
123
|
+
const getIdentity = moduleExport(loaded, "getCoreMigrationIdentity");
|
|
124
|
+
if (typeof getIdentity !== "function") {
|
|
125
|
+
throw new MigrateCommandError(
|
|
126
|
+
"The project-local emdash/migrations module does not export getCoreMigrationIdentity.",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return validateIdentity(await Reflect.apply(getIdentity, undefined, []));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function loadProjectMigrationExecutor(
|
|
133
|
+
projectRoot: string,
|
|
134
|
+
entrypoint: string,
|
|
135
|
+
): Promise<MigrationExecutorFactory> {
|
|
136
|
+
const loaded = await importProjectModule(projectRoot, entrypoint);
|
|
137
|
+
const factory = moduleExport(loaded, "createMigrationExecutor");
|
|
138
|
+
if (typeof factory !== "function") {
|
|
139
|
+
throw new MigrateCommandError(
|
|
140
|
+
`The project-local ${entrypoint} module does not export createMigrationExecutor.`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return (manifestConfig, context) => Reflect.apply(factory, undefined, [manifestConfig, context]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function findProjectRoot(start: string): Promise<string> {
|
|
147
|
+
let current = resolve(start);
|
|
148
|
+
const filesystemRoot = parse(current).root;
|
|
149
|
+
for (;;) {
|
|
150
|
+
try {
|
|
151
|
+
await readFile(resolve(current, "package.json"), "utf8");
|
|
152
|
+
return current;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (isRecord(error) && error.code !== "ENOENT" && error.code !== "ENOTDIR") {
|
|
155
|
+
throw new MigrateCommandError("Could not read the project package.json.");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (current === filesystemRoot) break;
|
|
159
|
+
current = dirname(current);
|
|
160
|
+
}
|
|
161
|
+
throw new MigrateCommandError("Could not find a project root containing package.json.");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function readMigrationManifestFile(
|
|
165
|
+
path: string,
|
|
166
|
+
isDefault: boolean,
|
|
167
|
+
): Promise<unknown> {
|
|
168
|
+
let source: string;
|
|
169
|
+
try {
|
|
170
|
+
source = await readFile(path, "utf8");
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (isDefault && isRecord(error) && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
173
|
+
throw new MigrateCommandError(
|
|
174
|
+
`No migration manifest found at ${path}. Build the project or use --from-config.`,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
throw new MigrateCommandError(`Could not read migration manifest: ${path}`);
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
return JSON.parse(source);
|
|
181
|
+
} catch {
|
|
182
|
+
throw new MigrateCommandError(`Migration manifest is not valid JSON: ${path}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function confirmWithReadline(message: string): Promise<boolean> {
|
|
187
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
188
|
+
try {
|
|
189
|
+
const answer = await prompt.question(`${message} [y/N] `);
|
|
190
|
+
return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
|
|
191
|
+
} finally {
|
|
192
|
+
prompt.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function onProcessSignal(signal: MigrationSignal, handler: () => Promise<void>): () => void {
|
|
197
|
+
const listener = () => {
|
|
198
|
+
void handler().finally(() => process.exit(MIGRATE_EXIT_CODES.interrupted));
|
|
199
|
+
};
|
|
200
|
+
process.once(signal, listener);
|
|
201
|
+
return () => process.removeListener(signal, listener);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const defaultDependencies: MigrateCommandDependencies = {
|
|
205
|
+
cwd: process.cwd(),
|
|
206
|
+
env: process.env,
|
|
207
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
208
|
+
findProjectRoot,
|
|
209
|
+
readManifest: readMigrationManifestFile,
|
|
210
|
+
buildManifestFromConfig: (projectRoot, configFile) =>
|
|
211
|
+
buildMigrationManifestFromConfig({ projectRoot, configFile }),
|
|
212
|
+
loadProjectIdentity: loadProjectMigrationIdentity,
|
|
213
|
+
loadProjectExecutor: loadProjectMigrationExecutor,
|
|
214
|
+
confirm: confirmWithReadline,
|
|
215
|
+
writeStdout: (value) => process.stdout.write(`${value}\n`),
|
|
216
|
+
writeStderr: (value) => process.stderr.write(`${value}\n`),
|
|
217
|
+
onSignal: onProcessSignal,
|
|
218
|
+
cleanupTimeoutMs: 2_000,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
function validateOptions(options: MigrateCommandOptions): void {
|
|
222
|
+
if (options.manifest && options.fromConfig) {
|
|
223
|
+
throw new MigrateCommandError("--manifest and --from-config cannot be used together.");
|
|
224
|
+
}
|
|
225
|
+
if (options.config && !options.fromConfig) {
|
|
226
|
+
throw new MigrateCommandError("--config requires --from-config.");
|
|
227
|
+
}
|
|
228
|
+
if (options.check && options.status) {
|
|
229
|
+
throw new MigrateCommandError("--check and --status cannot be used together.");
|
|
230
|
+
}
|
|
231
|
+
if (
|
|
232
|
+
options.expectedTargetFingerprint &&
|
|
233
|
+
!FINGERPRINT_PATTERN.test(options.expectedTargetFingerprint)
|
|
234
|
+
) {
|
|
235
|
+
throw new MigrateCommandError("--expected-target-fingerprint must be a SHA-256 fingerprint.");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function hasControlCharacter(value: string): boolean {
|
|
240
|
+
for (let index = 0; index < value.length; index++) {
|
|
241
|
+
const code = value.charCodeAt(index);
|
|
242
|
+
if (code <= 0x1f || code === 0x7f) return true;
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function targetField(value: unknown, name: string): string | undefined {
|
|
248
|
+
if (value === undefined) return undefined;
|
|
249
|
+
if (
|
|
250
|
+
typeof value !== "string" ||
|
|
251
|
+
value.length === 0 ||
|
|
252
|
+
hasControlCharacter(value) ||
|
|
253
|
+
CREDENTIAL_URL_PATTERN.test(value) ||
|
|
254
|
+
CREDENTIAL_QUERY_PATTERN.test(value)
|
|
255
|
+
) {
|
|
256
|
+
throw new MigrateCommandError(`The executor returned an unsafe migration target ${name}.`);
|
|
257
|
+
}
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function immutableTarget(value: unknown): Readonly<MigrationTarget> {
|
|
262
|
+
if (!isRecord(value)) {
|
|
263
|
+
throw new MigrateCommandError("The executor returned an invalid migration target.");
|
|
264
|
+
}
|
|
265
|
+
const kind = targetField(value.kind, "kind");
|
|
266
|
+
const label = targetField(value.label, "label");
|
|
267
|
+
const fingerprint = targetField(value.fingerprint, "fingerprint");
|
|
268
|
+
if (
|
|
269
|
+
!kind ||
|
|
270
|
+
!SAFE_TARGET_KIND_PATTERN.test(kind) ||
|
|
271
|
+
!label ||
|
|
272
|
+
!fingerprint ||
|
|
273
|
+
!FINGERPRINT_PATTERN.test(fingerprint)
|
|
274
|
+
) {
|
|
275
|
+
throw new MigrateCommandError("The executor returned an invalid migration target.");
|
|
276
|
+
}
|
|
277
|
+
const target: MigrationTarget = { kind, label, fingerprint };
|
|
278
|
+
const accountId = targetField(value.accountId, "accountId");
|
|
279
|
+
const environment = targetField(value.environment, "environment");
|
|
280
|
+
const resourceId = targetField(value.resourceId, "resourceId");
|
|
281
|
+
if (accountId) target.accountId = accountId;
|
|
282
|
+
if (environment) target.environment = environment;
|
|
283
|
+
if (resourceId) target.resourceId = resourceId;
|
|
284
|
+
return Object.freeze(target);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function safeMigrationNames(value: unknown, field: string): string[] {
|
|
288
|
+
if (
|
|
289
|
+
!Array.isArray(value) ||
|
|
290
|
+
!value.every((name) => typeof name === "string" && SAFE_MIGRATION_NAME_PATTERN.test(name))
|
|
291
|
+
) {
|
|
292
|
+
throw new MigrateCommandError(`The migration executor returned an invalid ${field} report.`);
|
|
293
|
+
}
|
|
294
|
+
return [...value];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function safeReport(value: unknown, target: Readonly<MigrationTarget>): MigrationReport {
|
|
298
|
+
if (!isRecord(value)) {
|
|
299
|
+
throw new MigrateCommandError("The migration executor returned an invalid report.");
|
|
300
|
+
}
|
|
301
|
+
const reportTarget = immutableTarget(value.target);
|
|
302
|
+
if (
|
|
303
|
+
reportTarget.kind !== target.kind ||
|
|
304
|
+
reportTarget.label !== target.label ||
|
|
305
|
+
reportTarget.fingerprint !== target.fingerprint ||
|
|
306
|
+
reportTarget.accountId !== target.accountId ||
|
|
307
|
+
reportTarget.environment !== target.environment ||
|
|
308
|
+
reportTarget.resourceId !== target.resourceId
|
|
309
|
+
) {
|
|
310
|
+
throw new MigrateCommandError(
|
|
311
|
+
"The migration executor report target does not match the confirmed target.",
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
target: { ...reportTarget },
|
|
316
|
+
knownApplied: safeMigrationNames(value.knownApplied, "knownApplied"),
|
|
317
|
+
pending: safeMigrationNames(value.pending, "pending"),
|
|
318
|
+
unknownApplied: safeMigrationNames(value.unknownApplied, "unknownApplied"),
|
|
319
|
+
executed: safeMigrationNames(value.executed, "executed"),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function printTarget(target: Readonly<MigrationTarget>, write: (value: string) => void): void {
|
|
324
|
+
write(`Migration target: ${target.kind} ${target.label}`);
|
|
325
|
+
if (target.accountId) write(`Account: ${target.accountId}`);
|
|
326
|
+
if (target.environment) write(`Environment: ${target.environment}`);
|
|
327
|
+
if (target.resourceId) write(`Resource: ${target.resourceId}`);
|
|
328
|
+
write(`Target fingerprint: ${target.fingerprint}`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function printNameSet(
|
|
332
|
+
label: string,
|
|
333
|
+
names: readonly string[],
|
|
334
|
+
write: (value: string) => void,
|
|
335
|
+
): void {
|
|
336
|
+
write(`${label}: ${names.length === 0 ? "none" : names.join(", ")}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function printHumanReport(report: MigrationReport, write: (value: string) => void): void {
|
|
340
|
+
printNameSet("Known applied", report.knownApplied, write);
|
|
341
|
+
printNameSet("Pending", report.pending, write);
|
|
342
|
+
printNameSet("Unknown applied", report.unknownApplied, write);
|
|
343
|
+
printNameSet("Executed", report.executed, write);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function reportExitCode(options: MigrateCommandOptions, report: MigrationReport): number {
|
|
347
|
+
if (!options.check) return MIGRATE_EXIT_CODES.success;
|
|
348
|
+
if (report.unknownApplied.length > 0) return MIGRATE_EXIT_CODES.unknownApplied;
|
|
349
|
+
if (report.pending.length > 0) return MIGRATE_EXIT_CODES.pending;
|
|
350
|
+
return MIGRATE_EXIT_CODES.success;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function createOverrides(options: MigrateCommandOptions): MigrationTargetOverrides {
|
|
354
|
+
return {
|
|
355
|
+
database: options.database,
|
|
356
|
+
databaseUrlEnv: options.databaseUrlEnv,
|
|
357
|
+
d1: options.d1,
|
|
358
|
+
accountId: options.accountId,
|
|
359
|
+
wranglerConfig: options.wranglerConfig,
|
|
360
|
+
wranglerEnv: options.wranglerEnv,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function bounded(
|
|
365
|
+
operation: Promise<void>,
|
|
366
|
+
timeoutMs: number,
|
|
367
|
+
): Promise<"complete" | "failed" | "timeout"> {
|
|
368
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
369
|
+
const timeout = new Promise<"timeout">((resolveTimeout) => {
|
|
370
|
+
timer = setTimeout(resolveTimeout, timeoutMs, "timeout");
|
|
371
|
+
});
|
|
372
|
+
const completion = operation.then<"complete", "failed">(
|
|
373
|
+
() => "complete",
|
|
374
|
+
() => "failed",
|
|
375
|
+
);
|
|
376
|
+
return Promise.race([completion, timeout]).finally(() => clearTimeout(timer));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async function loadManifest(
|
|
380
|
+
options: MigrateCommandOptions,
|
|
381
|
+
projectRoot: string,
|
|
382
|
+
dependencies: MigrateCommandDependencies,
|
|
383
|
+
): Promise<unknown> {
|
|
384
|
+
if (options.fromConfig) {
|
|
385
|
+
dependencies.writeStderr(
|
|
386
|
+
`Using trusted evaluated Astro configuration${options.config ? `: ${options.config}` : "."}`,
|
|
387
|
+
);
|
|
388
|
+
return dependencies.buildManifestFromConfig(projectRoot, options.config);
|
|
389
|
+
}
|
|
390
|
+
const isDefault = !options.manifest;
|
|
391
|
+
const path = options.manifest
|
|
392
|
+
? isAbsolute(options.manifest)
|
|
393
|
+
? options.manifest
|
|
394
|
+
: resolve(projectRoot, options.manifest)
|
|
395
|
+
: resolve(projectRoot, ".emdash/migrations.json");
|
|
396
|
+
return dependencies.readManifest(path, isDefault);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function redactExecutorMessage(
|
|
400
|
+
message: string,
|
|
401
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
402
|
+
): string {
|
|
403
|
+
let redacted = message
|
|
404
|
+
.replace(/[A-Za-z][A-Za-z0-9+.-]*:\/\/\S+/g, "[REDACTED_URL]")
|
|
405
|
+
.replace(
|
|
406
|
+
/\b(auth|credential|key|password|secret|signature|token)\s*[=:]\s*\S+/gi,
|
|
407
|
+
"$1=[REDACTED]",
|
|
408
|
+
);
|
|
409
|
+
for (const value of Object.values(env)) {
|
|
410
|
+
if (value && value.length >= 4) redacted = redacted.replaceAll(value, "[REDACTED]");
|
|
411
|
+
}
|
|
412
|
+
return redacted.replaceAll(/[\r\n\t]/g, " ").slice(0, 1_000);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function safeCommandMessage(
|
|
416
|
+
error: unknown,
|
|
417
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
418
|
+
): string {
|
|
419
|
+
if (error instanceof MigrateCommandError || error instanceof MigrationManifestValidationError) {
|
|
420
|
+
return error.message;
|
|
421
|
+
}
|
|
422
|
+
if (error instanceof Error && error.message) return redactExecutorMessage(error.message, env);
|
|
423
|
+
return "Migration command failed. Check the project configuration, target, and credentials.";
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function runMigrateCommand(
|
|
427
|
+
options: MigrateCommandOptions,
|
|
428
|
+
dependencies: MigrateCommandDependencies = defaultDependencies,
|
|
429
|
+
): Promise<number> {
|
|
430
|
+
let executor: MigrationExecutor | undefined;
|
|
431
|
+
let disposePromise: Promise<void> | undefined;
|
|
432
|
+
let interrupted = false;
|
|
433
|
+
let primaryFailure = false;
|
|
434
|
+
let exitCode: number = MIGRATE_EXIT_CODES.error;
|
|
435
|
+
const interruptedResult = Symbol("interrupted");
|
|
436
|
+
let resolveInterruption: (() => void) | undefined;
|
|
437
|
+
const interruption = new Promise<typeof interruptedResult>((resolveInterrupted) => {
|
|
438
|
+
resolveInterruption = () => resolveInterrupted(interruptedResult);
|
|
439
|
+
});
|
|
440
|
+
const dispose = () => {
|
|
441
|
+
disposePromise ??= executor?.dispose?.() ?? Promise.resolve();
|
|
442
|
+
return disposePromise;
|
|
443
|
+
};
|
|
444
|
+
const removeSignalHandlers: (() => void)[] = [];
|
|
445
|
+
|
|
446
|
+
const execute = async (): Promise<number> => {
|
|
447
|
+
try {
|
|
448
|
+
validateOptions(options);
|
|
449
|
+
const projectRoot = await dependencies.findProjectRoot(dependencies.cwd);
|
|
450
|
+
const unvalidatedManifest = await loadManifest(options, projectRoot, dependencies);
|
|
451
|
+
const identity = await dependencies.loadProjectIdentity(projectRoot);
|
|
452
|
+
const manifest: MigrationManifestV1 = await validateMigrationManifest(
|
|
453
|
+
unvalidatedManifest,
|
|
454
|
+
identity,
|
|
455
|
+
);
|
|
456
|
+
const factory = await dependencies.loadProjectExecutor(
|
|
457
|
+
projectRoot,
|
|
458
|
+
manifest.database.executorEntrypoint,
|
|
459
|
+
);
|
|
460
|
+
executor = await factory(manifest.database.executorConfig, {
|
|
461
|
+
projectRoot,
|
|
462
|
+
env: dependencies.env,
|
|
463
|
+
overrides: createOverrides(options),
|
|
464
|
+
});
|
|
465
|
+
const target = immutableTarget(executor.target);
|
|
466
|
+
printTarget(target, dependencies.writeStderr);
|
|
467
|
+
|
|
468
|
+
const onSignal = async () => {
|
|
469
|
+
interrupted = true;
|
|
470
|
+
await bounded(dispose(), dependencies.cleanupTimeoutMs);
|
|
471
|
+
resolveInterruption?.();
|
|
472
|
+
};
|
|
473
|
+
removeSignalHandlers.push(
|
|
474
|
+
dependencies.onSignal("SIGINT", onSignal),
|
|
475
|
+
dependencies.onSignal("SIGTERM", onSignal),
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
const applying = !options.check && !options.status;
|
|
479
|
+
if (applying && target.kind === "d1") {
|
|
480
|
+
dependencies.writeStderr(
|
|
481
|
+
"Warning: D1 migration jobs must be serialized externally by Cloudflare account and database UUID; this command does not coordinate concurrent applies.",
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
if (applying) {
|
|
485
|
+
if (options.expectedTargetFingerprint) {
|
|
486
|
+
if (options.expectedTargetFingerprint !== target.fingerprint) {
|
|
487
|
+
dependencies.writeStderr("Expected target fingerprint does not match the target.");
|
|
488
|
+
exitCode = MIGRATE_EXIT_CODES.confirmation;
|
|
489
|
+
return exitCode;
|
|
490
|
+
}
|
|
491
|
+
} else if (!dependencies.interactive || options.json) {
|
|
492
|
+
dependencies.writeStderr(
|
|
493
|
+
"Noninteractive apply requires --expected-target-fingerprint with the displayed fingerprint.",
|
|
494
|
+
);
|
|
495
|
+
exitCode = MIGRATE_EXIT_CODES.confirmation;
|
|
496
|
+
return exitCode;
|
|
497
|
+
} else if (!(await dependencies.confirm(`Apply EmDash migrations to ${target.label}?`))) {
|
|
498
|
+
dependencies.writeStderr("Migration cancelled.");
|
|
499
|
+
exitCode = MIGRATE_EXIT_CODES.confirmation;
|
|
500
|
+
return exitCode;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const rawReport = await Promise.race([
|
|
505
|
+
executor.execute({
|
|
506
|
+
action: applying ? "apply" : "check",
|
|
507
|
+
i18n: manifest.i18n,
|
|
508
|
+
artifact: {
|
|
509
|
+
emdashVersion: manifest.emdashVersion,
|
|
510
|
+
migrationSetFingerprint: manifest.migrationSet.fingerprint,
|
|
511
|
+
},
|
|
512
|
+
}),
|
|
513
|
+
interruption,
|
|
514
|
+
]);
|
|
515
|
+
if (rawReport === interruptedResult || interrupted) {
|
|
516
|
+
exitCode = MIGRATE_EXIT_CODES.interrupted;
|
|
517
|
+
return exitCode;
|
|
518
|
+
}
|
|
519
|
+
const report = safeReport(rawReport, target);
|
|
520
|
+
if (options.json) {
|
|
521
|
+
dependencies.writeStdout(JSON.stringify(report));
|
|
522
|
+
} else {
|
|
523
|
+
printHumanReport(report, dependencies.writeStdout);
|
|
524
|
+
}
|
|
525
|
+
exitCode = reportExitCode(options, report);
|
|
526
|
+
return exitCode;
|
|
527
|
+
} catch (error) {
|
|
528
|
+
primaryFailure = true;
|
|
529
|
+
dependencies.writeStderr(safeCommandMessage(error, dependencies.env));
|
|
530
|
+
exitCode = interrupted ? MIGRATE_EXIT_CODES.interrupted : MIGRATE_EXIT_CODES.error;
|
|
531
|
+
return exitCode;
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
try {
|
|
536
|
+
exitCode = await execute();
|
|
537
|
+
} finally {
|
|
538
|
+
for (const remove of removeSignalHandlers) remove();
|
|
539
|
+
if (executor) {
|
|
540
|
+
const cleanup = await bounded(dispose(), dependencies.cleanupTimeoutMs);
|
|
541
|
+
if (cleanup !== "complete" && !primaryFailure && !interrupted) {
|
|
542
|
+
dependencies.writeStderr("Migration executor cleanup failed.");
|
|
543
|
+
exitCode = MIGRATE_EXIT_CODES.error;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return exitCode;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export const migrateCommand = defineCommand({
|
|
551
|
+
meta: {
|
|
552
|
+
name: "migrate",
|
|
553
|
+
description: "Check or apply deployment-managed EmDash migrations",
|
|
554
|
+
},
|
|
555
|
+
args: {
|
|
556
|
+
manifest: { type: "string", description: "Migration manifest path" },
|
|
557
|
+
"from-config": { type: "boolean", description: "Build the manifest from Astro config" },
|
|
558
|
+
config: { type: "string", description: "Astro config path (requires --from-config)" },
|
|
559
|
+
check: { type: "boolean", description: "Check for pending or unknown migrations" },
|
|
560
|
+
status: { type: "boolean", description: "Report all migration status sets" },
|
|
561
|
+
json: { type: "boolean", description: "Print the stable JSON report" },
|
|
562
|
+
"expected-target-fingerprint": {
|
|
563
|
+
type: "string",
|
|
564
|
+
description: "Required target fingerprint for noninteractive apply",
|
|
565
|
+
},
|
|
566
|
+
database: { type: "string", description: "Override the SQLite database path" },
|
|
567
|
+
"database-url-env": {
|
|
568
|
+
type: "string",
|
|
569
|
+
description: "Override the database URL environment-variable name",
|
|
570
|
+
},
|
|
571
|
+
d1: { type: "string", description: "Override the D1 database UUID or name" },
|
|
572
|
+
"account-id": { type: "string", description: "Override the Cloudflare account ID" },
|
|
573
|
+
"wrangler-config": { type: "string", description: "Override the Wrangler config path" },
|
|
574
|
+
"wrangler-env": { type: "string", description: "Override the Wrangler environment" },
|
|
575
|
+
},
|
|
576
|
+
async run({ args }) {
|
|
577
|
+
process.exitCode = await runMigrateCommand({
|
|
578
|
+
manifest: args.manifest,
|
|
579
|
+
fromConfig: args["from-config"],
|
|
580
|
+
config: args.config,
|
|
581
|
+
check: args.check,
|
|
582
|
+
status: args.status,
|
|
583
|
+
json: args.json,
|
|
584
|
+
expectedTargetFingerprint: args["expected-target-fingerprint"],
|
|
585
|
+
database: args.database,
|
|
586
|
+
databaseUrlEnv: args["database-url-env"],
|
|
587
|
+
d1: args.d1,
|
|
588
|
+
accountId: args["account-id"],
|
|
589
|
+
wranglerConfig: args["wrangler-config"],
|
|
590
|
+
wranglerEnv: args["wrangler-env"],
|
|
591
|
+
});
|
|
592
|
+
},
|
|
593
|
+
});
|
package/src/cli/index.ts
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* EmDash CLI
|
|
5
|
-
*
|
|
6
|
-
* Built with citty + clack (same stack as Nuxt CLI)
|
|
7
|
-
*
|
|
8
|
-
* Commands:
|
|
9
|
-
* - init: Bootstrap database from template config, or interactive setup
|
|
10
|
-
* - types: Generate TypeScript types from schema
|
|
11
|
-
* - dev: [DEPRECATED, hidden] Run dev server with a local SQLite database
|
|
12
|
-
* - seed: Apply a seed file to the database
|
|
13
|
-
* - export-seed: Export database schema and content as a seed file
|
|
14
|
-
* - secrets: Generate and inspect EmDash secrets (encryption keys, etc.)
|
|
15
|
-
* - auth: [DEPRECATED] Generate auth secret (use `secrets` instead)
|
|
16
|
-
* - login/logout/whoami: Session management
|
|
17
|
-
* - content: Create, read, update, delete content
|
|
18
|
-
* - schema: Manage collections and fields
|
|
19
|
-
* - media: Upload and manage media
|
|
20
|
-
* - search: Full-text search
|
|
21
|
-
* - taxonomy: Manage taxonomies and terms
|
|
22
|
-
* - menu: Manage navigation menus
|
|
23
|
-
* - plugin: Plugin management (init, bundle, validate, publish, login, logout)
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
3
|
import { defineCommand, runMain } from "citty";
|
|
27
4
|
|
|
28
5
|
import { authCommand } from "./commands/auth.js";
|
|
@@ -34,6 +11,7 @@ import { initCommand } from "./commands/init.js";
|
|
|
34
11
|
import { loginCommand, logoutCommand, whoamiCommand } from "./commands/login.js";
|
|
35
12
|
import { mediaCommand } from "./commands/media.js";
|
|
36
13
|
import { menuCommand } from "./commands/menu.js";
|
|
14
|
+
import { migrateCommand } from "./commands/migrate.js";
|
|
37
15
|
import { pluginCommand } from "./commands/plugin.js";
|
|
38
16
|
import { schemaCommand } from "./commands/schema.js";
|
|
39
17
|
import { searchCommand } from "./commands/search-cmd.js";
|
|
@@ -54,6 +32,7 @@ const main = defineCommand({
|
|
|
54
32
|
dev: devCommand,
|
|
55
33
|
doctor: doctorCommand,
|
|
56
34
|
seed: seedCommand,
|
|
35
|
+
migrate: migrateCommand,
|
|
57
36
|
"export-seed": exportSeedCommand,
|
|
58
37
|
secrets: secretsCommand,
|
|
59
38
|
// Deprecated alias kept for backwards compat; will be removed in a future minor.
|