UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 18 kB
{"version":3,"file":"migrate.mjs","names":["cliLogger","syncServices.syncCollections"],"sources":["../../../../src/libs/cli/commands/migrate.ts"],"sourcesContent":["import { confirm } from \"@inquirer/prompts\";\nimport { syncServices } from \"../../../services/index.js\";\nimport type {\n\tConfig,\n\tEnvironmentVariables,\n\tServiceContext,\n} from \"../../../types.js\";\nimport createServiceContext from \"../../../utils/services/create-service-context.js\";\nimport applyCollectionMigrations from \"../../collection/apply-collection-migrations.js\";\nimport assessMigrationPlans from \"../../collection/migration/assess-migration-plan.js\";\nimport planCollectionMigrations from \"../../collection/plan-collection-migrations.js\";\nimport loadConfigFile from \"../../config/load-config-file.js\";\nimport { prepareExternalMigrations } from \"../../db/load-external-migrations.js\";\nimport type { DatabaseConnection } from \"../../db/types.js\";\nimport prepareTranslations from \"../../i18n/prepare-translations.js\";\nimport type { TranslationStore } from \"../../i18n/types.js\";\nimport {\n\tdestroyKVAdapter,\n\tgetInitializedKVAdapter,\n} from \"../../kv/lifecycle.js\";\nimport type { KVAdapterInstance } from \"../../kv/types.js\";\nimport {\n\tstartLoggerBuffering,\n\tstopLoggerBuffering,\n} from \"../../logger/index.js\";\nimport type { AdapterRuntimeContext } from \"../../runtime/types.js\";\nimport cliLogger from \"../logger.js\";\nimport {\n\ttype MigrationApprovalAction,\n\trequiresPostMigrationApproval,\n\tresolveMigrationApproval,\n} from \"../services/migration-approval.js\";\nimport { reportMigrationAssessment } from \"../services/migration-report.js\";\nimport runSyncTasks from \"../services/run-sync-tasks.js\";\nimport validateEnvVars from \"../services/validate-env-vars.js\";\n\ntype MigrateCommandOptions = {\n\tskipSyncSteps?: boolean;\n\tskipEnvValidation?: boolean;\n\tyes?: boolean;\n\tallowDestructive?: boolean;\n\tremote?: boolean;\n};\n\n/** Runs an interactive approval gate and reports non-interactive policy errors. */\nconst requestMigrationApproval = async (\n\taction: MigrationApprovalAction,\n): Promise<boolean> => {\n\tif (action === \"proceed\") return true;\n\tif (action === \"reject-destructive\") {\n\t\tcliLogger.error(\n\t\t\t\"--yes does not authorize destructive collection migrations. Re-run with --allow-destructive if you accept the risk of permanent data loss.\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tconst destructive = action === \"prompt-destructive\";\n\ttry {\n\t\treturn await confirm({\n\t\t\tmessage: destructive\n\t\t\t\t? \"These collection migrations may permanently delete stored data. Do you want to continue?\"\n\t\t\t\t: \"These migrations require review. Do you want to continue?\",\n\t\t\tdefault: false,\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof Error && error.name === \"ExitPromptError\")\n\t\t\treturn false;\n\t\tthrow error;\n\t}\n};\n\n/** Runs database and risk-aware collection migrations for CLI/runtime callers. */\nconst migrateCommand = (props?: {\n\tconfig?: Config;\n\tenv?: EnvironmentVariables;\n\truntimeContext?: AdapterRuntimeContext;\n\ttranslationStore?: TranslationStore;\n\tprojectRoot?: string;\n\tmode: \"process\" | \"return\";\n}) => {\n\treturn async (options?: MigrateCommandOptions) => {\n\t\tlet config: Config | undefined;\n\t\tlet env: EnvironmentVariables | undefined = props?.env;\n\t\tlet runtimeContext: AdapterRuntimeContext | undefined =\n\t\t\tprops?.runtimeContext;\n\t\tlet translationStore: TranslationStore | undefined;\n\t\tlet kvInstance: KVAdapterInstance | undefined;\n\t\tlet database: DatabaseConnection | undefined;\n\t\tconst mode = props?.mode ?? \"process\";\n\n\t\t/** Destroys adapters initialized during this migration command. */\n\t\tconst cleanupAdapters = async (): Promise<void> => {\n\t\t\tif (config) {\n\t\t\t\tawait Promise.allSettled([\n\t\t\t\t\tdatabase?.destroy(),\n\t\t\t\t\tdestroyKVAdapter(kvInstance, {\n\t\t\t\t\t\tconfig,\n\t\t\t\t\t\tenv,\n\t\t\t\t\t\truntimeContext,\n\t\t\t\t\t}),\n\t\t\t\t]);\n\t\t\t}\n\t\t\tdatabase = undefined;\n\t\t\tkvInstance = undefined;\n\t\t};\n\n\t\t/** Stops the command with the requested process status or a false result. */\n\t\tconst stopCommand = async (exitCode: number): Promise<false> => {\n\t\t\tawait cleanupAdapters();\n\t\t\tif (mode === \"process\") {\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(exitCode);\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\ttry {\n\t\t\tstartLoggerBuffering();\n\t\t\tconst startTime = cliLogger.startTimer();\n\t\t\tconst skipSyncSteps = options?.skipSyncSteps ?? false;\n\t\t\tconst yes = options?.yes ?? false;\n\t\t\tconst allowDestructive = options?.allowDestructive ?? false;\n\t\t\tlet projectRoot = props?.projectRoot;\n\n\t\t\t//* preflight: load and validate the project, then prepare all migrations\n\t\t\tif (props?.config) {\n\t\t\t\tconfig = props.config;\n\t\t\t\ttranslationStore = props.translationStore;\n\t\t\t} else {\n\t\t\t\tconst res = await loadConfigFile({ prepareRuntime: true });\n\t\t\t\tconfig = res.config;\n\t\t\t\tenv = res.env;\n\t\t\t\truntimeContext = res.runtimeContext;\n\t\t\t\tprojectRoot = res.projectRoot;\n\t\t\t\ttranslationStore = (\n\t\t\t\t\tawait prepareTranslations({\n\t\t\t\t\t\tconfig,\n\t\t\t\t\t\tprojectRoot: res.projectRoot,\n\t\t\t\t\t})\n\t\t\t\t).translationStore;\n\n\t\t\t\tif (options?.skipEnvValidation !== true) {\n\t\t\t\t\tconst envValid = await validateEnvVars({\n\t\t\t\t\t\tenvSchema: res.envSchema,\n\t\t\t\t\t\tenv: res.env,\n\t\t\t\t\t});\n\t\t\t\t\tif (!envValid) return await stopCommand(1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!config || !translationStore) {\n\t\t\t\tthrow new Error(\"Lucid could not resolve its migration configuration.\");\n\t\t\t}\n\t\t\tdatabase = await config.db.connect(env);\n\n\t\t\tawait prepareExternalMigrations(config, projectRoot);\n\n\t\t\tconst preflightContext = createServiceContext({\n\t\t\t\tconfig,\n\t\t\t\tdatabase,\n\t\t\t\ttranslationStore,\n\t\t\t\tenv,\n\t\t\t\truntimeContext,\n\t\t\t});\n\n\t\t\tcliLogger.info(\"Checking the migration status\");\n\t\t\tconst initialPlanResult =\n\t\t\t\tawait planCollectionMigrations(preflightContext);\n\t\t\tif (initialPlanResult.error) {\n\t\t\t\tcliLogger.error(\n\t\t\t\t\t\"Could not plan collection migrations:\",\n\t\t\t\t\tpreflightContext.translate.english(initialPlanResult.error.message) ||\n\t\t\t\t\t\t\"Unknown error\",\n\t\t\t\t);\n\t\t\t\treturn await stopCommand(1);\n\t\t\t}\n\t\t\tconst initialAssessment = assessMigrationPlans(\n\t\t\t\tinitialPlanResult.data.collections.map(\n\t\t\t\t\t({ migrationPlan }) => migrationPlan,\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst needsCollectionMigrations = initialAssessment.reasons.length > 0;\n\t\t\tconst needsDatabaseMigrations = await config.db.needsMigration(\n\t\t\t\tdatabase.client,\n\t\t\t);\n\n\t\t\tif (needsDatabaseMigrations) {\n\t\t\t\tcliLogger.warn(\n\t\t\t\t\t\"Database schema migrations are pending and require approval because their migration bodies cannot be classified.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (needsCollectionMigrations) {\n\t\t\t\treportMigrationAssessment(initialAssessment);\n\t\t\t}\n\n\t\t\t//* no-op path: keep sync behavior but avoid initializing migration adapters\n\t\t\tif (!needsDatabaseMigrations && !needsCollectionMigrations) {\n\t\t\t\tcliLogger.success(\"No migrations are required\");\n\t\t\t\tif (!skipSyncSteps) {\n\t\t\t\t\tconst syncResult = await runSyncTasks({\n\t\t\t\t\t\tconfig,\n\t\t\t\t\t\tdatabase,\n\t\t\t\t\t\ttranslationStore,\n\t\t\t\t\t\tenv,\n\t\t\t\t\t\truntimeContext,\n\t\t\t\t\t});\n\t\t\t\t\tif (!syncResult) return await stopCommand(1);\n\t\t\t\t}\n\n\t\t\t\tconst endTime = startTime();\n\t\t\t\tcliLogger.success(\n\t\t\t\t\t\"Migrations completed\",\n\t\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\t\t\"in\",\n\t\t\t\t\tcliLogger.color.green(cliLogger.formatMilliseconds(endTime)),\n\t\t\t\t);\n\t\t\t\tawait cleanupAdapters();\n\t\t\t\tif (mode === \"process\") {\n\t\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t//* approval: safe collection-only plans bypass this gate\n\t\t\tconst initialApproval = resolveMigrationApproval({\n\t\t\t\tassessment: initialAssessment,\n\t\t\t\thasPendingDatabaseMigrations: needsDatabaseMigrations,\n\t\t\t\tyes,\n\t\t\t\tallowDestructive,\n\t\t\t});\n\t\t\tconst initiallyApproved = await requestMigrationApproval(initialApproval);\n\t\t\tif (!initiallyApproved) {\n\t\t\t\tif (initialApproval === \"reject-destructive\") {\n\t\t\t\t\treturn await stopCommand(1);\n\t\t\t\t}\n\t\t\t\tcliLogger.info(\"Exiting without running migrations.\");\n\t\t\t\treturn await stopCommand(0);\n\t\t\t}\n\n\t\t\tkvInstance = await getInitializedKVAdapter(config, {\n\t\t\t\tenv,\n\t\t\t\truntimeContext,\n\t\t\t});\n\t\t\tconst executionContext: ServiceContext = {\n\t\t\t\t...preflightContext,\n\t\t\t\tkv: kvInstance,\n\t\t\t};\n\n\t\t\t//* execution: arbitrary database migrations run before collection re-planning\n\t\t\tif (needsDatabaseMigrations) {\n\t\t\t\tcliLogger.info(\"Running database schema migrations...\");\n\t\t\t\tawait config.db.migrateToLatest(database);\n\t\t\t\tcliLogger.success(\n\t\t\t\t\t\"Schema migrations completed\",\n\t\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst exactPlanResult = needsDatabaseMigrations\n\t\t\t\t? await planCollectionMigrations(executionContext)\n\t\t\t\t: initialPlanResult;\n\t\t\tif (exactPlanResult.error) {\n\t\t\t\tcliLogger.error(\n\t\t\t\t\t\"Could not re-plan collection migrations after database migrations:\",\n\t\t\t\t\texecutionContext.translate.english(exactPlanResult.error.message) ||\n\t\t\t\t\t\t\"Unknown error\",\n\t\t\t\t);\n\t\t\t\treturn await stopCommand(1);\n\t\t\t}\n\t\t\tconst exactAssessment = assessMigrationPlans(\n\t\t\t\texactPlanResult.data.collections.map(\n\t\t\t\t\t({ migrationPlan }) => migrationPlan,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tif (needsDatabaseMigrations && exactAssessment.reasons.length > 0) {\n\t\t\t\tcliLogger.info(\"Post-migration collection plan:\");\n\t\t\t\treportMigrationAssessment(exactAssessment);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tneedsDatabaseMigrations &&\n\t\t\t\trequiresPostMigrationApproval(initialAssessment, exactAssessment)\n\t\t\t) {\n\t\t\t\tcliLogger.warn(\n\t\t\t\t\t\"The collection migration risk increased after database migrations ran.\",\n\t\t\t\t);\n\t\t\t\tconst increasedRiskApproval = resolveMigrationApproval({\n\t\t\t\t\tassessment: exactAssessment,\n\t\t\t\t\thasPendingDatabaseMigrations: false,\n\t\t\t\t\tyes,\n\t\t\t\t\tallowDestructive,\n\t\t\t\t});\n\t\t\t\tconst increasedRiskApproved = await requestMigrationApproval(\n\t\t\t\t\tincreasedRiskApproval,\n\t\t\t\t);\n\t\t\t\tif (!increasedRiskApproved) {\n\t\t\t\t\treturn await stopCommand(\n\t\t\t\t\t\tincreasedRiskApproval === \"reject-destructive\" ? 1 : 0,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst exactCollectionMigrations = exactAssessment.reasons.length > 0;\n\t\t\tif (exactCollectionMigrations) {\n\t\t\t\tconst preCollectionSyncResult =\n\t\t\t\t\tawait syncServices.syncCollections(executionContext);\n\t\t\t\tif (preCollectionSyncResult.error) {\n\t\t\t\t\tcliLogger.error(\n\t\t\t\t\t\t\"Sync failed during pre-migration collection sync:\",\n\t\t\t\t\t\texecutionContext.translate.english(\n\t\t\t\t\t\t\tpreCollectionSyncResult.error.message,\n\t\t\t\t\t\t) || \"Unknown error\",\n\t\t\t\t\t);\n\t\t\t\t\treturn await stopCommand(1);\n\t\t\t\t}\n\n\t\t\t\tcliLogger.info(\"Running collection migrations...\");\n\t\t\t\tconst migrationResult = await applyCollectionMigrations(\n\t\t\t\t\texecutionContext,\n\t\t\t\t\texactPlanResult.data,\n\t\t\t\t);\n\t\t\t\tif (migrationResult.error) {\n\t\t\t\t\tcliLogger.error(\n\t\t\t\t\t\t\"Collection migrations failed:\",\n\t\t\t\t\t\texecutionContext.translate.english(migrationResult.error.message) ||\n\t\t\t\t\t\t\t\"Unknown error\",\n\t\t\t\t\t);\n\t\t\t\t\treturn await stopCommand(1);\n\t\t\t\t}\n\t\t\t\tcliLogger.success(\n\t\t\t\t\t\"Collection migrations completed\",\n\t\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t//* sync and cache clearing run only after the exact plan has succeeded\n\t\t\tif (!skipSyncSteps) {\n\t\t\t\tconst syncResult = await runSyncTasks({\n\t\t\t\t\tconfig,\n\t\t\t\t\tdatabase,\n\t\t\t\t\ttranslationStore,\n\t\t\t\t\tkv: kvInstance,\n\t\t\t\t\tenv,\n\t\t\t\t\truntimeContext,\n\t\t\t\t});\n\t\t\t\tif (!syncResult) return await stopCommand(1);\n\t\t\t}\n\n\t\t\tcliLogger.info(\"Clearing KV cache...\");\n\t\t\tawait kvInstance.clear(\n\t\t\t\tcreateServiceContext({\n\t\t\t\t\tconfig,\n\t\t\t\t\tdatabase,\n\t\t\t\t\ttranslationStore,\n\t\t\t\t\tenv,\n\t\t\t\t\truntimeContext,\n\t\t\t\t\tqueue: executionContext.queue,\n\t\t\t\t\tkv: kvInstance,\n\t\t\t\t\tmedia: executionContext.media,\n\t\t\t\t\temail: executionContext.email,\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tconst endTime = startTime();\n\t\t\tawait cleanupAdapters();\n\t\t\tif (mode === \"process\") {\n\t\t\t\tcliLogger.log(\n\t\t\t\t\tcliLogger.createBadge(\"LUCID CMS\"),\n\t\t\t\t\t\"Migrations completed\",\n\t\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\t\t\"in\",\n\t\t\t\t\tcliLogger.color.green(cliLogger.formatMilliseconds(endTime)),\n\t\t\t\t\t{ spaceAfter: true, spaceBefore: true },\n\t\t\t\t);\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\n\t\t\tcliLogger.success(\n\t\t\t\t\"Migrations completed\",\n\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\t\"in\",\n\t\t\t\tcliLogger.color.green(cliLogger.formatMilliseconds(endTime)),\n\t\t\t);\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tcliLogger.errorInstance(error, \"Migration failed\");\n\t\t\t} else {\n\t\t\t\tcliLogger.error(\"Migration failed\", \"Unknown error\");\n\t\t\t}\n\t\t\treturn await stopCommand(1);\n\t\t}\n\t};\n};\n\nexport default migrateCommand;\n"],"mappings":"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"}