@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 12.8 kB
Source Map (JSON)
{"version":3,"file":"migrate-rollback.mjs","names":["cliLogger","constants"],"sources":["../../../../src/libs/cli/commands/migrate-rollback.ts"],"sourcesContent":["import { confirm } from \"@inquirer/prompts\";\nimport { sql } from \"kysely\";\nimport { Migrator } from \"kysely/migration\";\nimport constants from \"../../../constants/constants.js\";\nimport type { Config, EnvironmentVariables } from \"../../../types.js\";\nimport createServiceContext from \"../../../utils/services/create-service-context.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 logger, {\n\tstartLoggerBuffering,\n\tstopLoggerBuffering,\n} from \"../../logger/index.js\";\nimport type { AdapterRuntimeContext } from \"../../runtime/types.js\";\nimport cliLogger from \"../logger.js\";\nimport validateEnvVars from \"../services/validate-env-vars.js\";\n\nconst migrateRollbackCommand = async (options?: {\n\tforce?: boolean;\n\tremote?: boolean;\n\tsteps?: number;\n}) => {\n\tlet kvInstance: KVAdapterInstance | undefined;\n\tlet config: Config | undefined;\n\tlet env: EnvironmentVariables | undefined;\n\tlet runtimeContext: AdapterRuntimeContext | undefined;\n\tlet translationStore: TranslationStore | undefined;\n\tlet database: DatabaseConnection | undefined;\n\n\tconst cleanup = async () => {\n\t\tif (!config) return;\n\t\tawait Promise.allSettled([\n\t\t\tdatabase?.destroy(),\n\t\t\tdestroyKVAdapter(kvInstance, { config, env, runtimeContext }),\n\t\t]);\n\t\tdatabase = undefined;\n\t\tkvInstance = undefined;\n\t};\n\ttry {\n\t\tstartLoggerBuffering();\n\t\tconst startTime = cliLogger.startTimer();\n\t\tconst steps = options?.steps ?? 1;\n\t\tconst force = options?.force ?? false;\n\n\t\tconst res = await loadConfigFile({\n\t\t\tprepareRuntime: true,\n\t\t});\n\t\tconfig = res.config;\n\t\tenv = res.env;\n\t\truntimeContext = res.runtimeContext;\n\t\ttranslationStore = (\n\t\t\tawait prepareTranslations({\n\t\t\t\tconfig,\n\t\t\t\tprojectRoot: res.projectRoot,\n\t\t\t})\n\t\t).translationStore;\n\n\t\tconst envValid = await validateEnvVars({\n\t\t\tenvSchema: res.envSchema,\n\t\t\tenv: res.env,\n\t\t});\n\n\t\tif (!envValid) {\n\t\t\tawait cleanup();\n\t\t\tawait stopLoggerBuffering();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tcliLogger.info(\"Checking rollback status\");\n\n\t\tawait prepareExternalMigrations(config, res.projectRoot);\n\t\tdatabase = await config.db.connect(env);\n\n\t\tconst migrator = new Migrator({\n\t\t\tdb: database.client,\n\t\t\tprovider: {\n\t\t\t\tasync getMigrations() {\n\t\t\t\t\treturn res.config.db.migrations;\n\t\t\t\t},\n\t\t\t},\n\t\t\t//* required so new core migrations can run after external migrations have executed\n\t\t\tallowUnorderedMigrations: true,\n\t\t});\n\n\t\t//* executed migrations that are no longer registered would fail the rollback midway, so surface them upfront\n\t\tconst availableMigrationNames = Object.keys(res.config.db.migrations);\n\t\tlet executedMigrationNames: string[] = [];\n\t\ttry {\n\t\t\tconst executedRows = await sql<{ name: string }>`\n\t\t\t\tSELECT name FROM kysely_migration\n\t\t\t`.execute(database.client);\n\t\t\texecutedMigrationNames = executedRows.rows.map((row) => row.name);\n\t\t} catch (_) {\n\t\t\t//* the migration table doesnt exist yet - no migrations to rollback\n\t\t}\n\n\t\tconst missingMigrations = executedMigrationNames.filter(\n\t\t\t(name) => !availableMigrationNames.includes(name),\n\t\t);\n\t\tif (missingMigrations.length > 0) {\n\t\t\tcliLogger.error(\n\t\t\t\t`Cannot rollback: previously executed migration(s) are no longer registered: ${missingMigrations.join(\", \")}`,\n\t\t\t);\n\t\t\tcliLogger.info(\n\t\t\t\t\"If you removed a plugin or migration file, restore it so its migrations can be rolled back.\",\n\t\t\t);\n\t\t\tawait cleanup();\n\t\t\tawait stopLoggerBuffering();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst migrations = await migrator.getMigrations();\n\t\t//* rollbacks happen in execution order, which can diverge from name order with external migrations\n\t\tconst executedMigrations = migrations\n\t\t\t.filter((m) => m.executedAt !== undefined)\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst aTime = a.executedAt?.getTime() ?? 0;\n\t\t\t\tconst bTime = b.executedAt?.getTime() ?? 0;\n\t\t\t\tif (aTime === bTime) return a.name.localeCompare(b.name);\n\t\t\t\treturn aTime - bTime;\n\t\t\t});\n\n\t\tif (executedMigrations.length === 0) {\n\t\t\tcliLogger.info(\"No migrations to rollback\");\n\t\t\tawait cleanup();\n\t\t\tawait stopLoggerBuffering();\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tconst protectedMigrations = config.db.protectedMigrations;\n\t\tconst migrationsToRollback: string[] = [];\n\n\t\tfor (\n\t\t\tlet i = executedMigrations.length - 1;\n\t\t\ti >= 0 && migrationsToRollback.length < steps;\n\t\t\ti--\n\t\t) {\n\t\t\tconst migration = executedMigrations[i];\n\t\t\tif (!migration) continue;\n\n\t\t\tif (protectedMigrations.includes(migration.name)) {\n\t\t\t\tcliLogger.error(\n\t\t\t\t\t`Cannot rollback protected migration: \"${migration.name}\"`,\n\t\t\t\t);\n\t\t\t\tcliLogger.info(\n\t\t\t\t\t\"Protected migrations are essential for the CMS to function and cannot be rolled back.\",\n\t\t\t\t);\n\t\t\t\tcliLogger.info(\n\t\t\t\t\t\"If you need to reset the database, use\",\n\t\t\t\t\tcliLogger.color.cyan(\"migrate:reset\"),\n\t\t\t\t\t\"or\",\n\t\t\t\t\tcliLogger.color.cyan(\"migrate:fresh\"),\n\t\t\t\t);\n\t\t\t\tawait cleanup();\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tmigrationsToRollback.push(migration.name);\n\t\t}\n\n\t\tcliLogger.info(`Found ${executedMigrations.length} executed migration(s)`);\n\t\tcliLogger.warn(\n\t\t\t`Preparing to rollback ${migrationsToRollback.length} migration(s)`,\n\t\t);\n\n\t\tif (!force) {\n\t\t\tlet shouldProceed: boolean;\n\t\t\ttry {\n\t\t\t\tshouldProceed = await confirm({\n\t\t\t\t\tmessage: `Are you sure you want to rollback ${migrationsToRollback.length} migration(s)? This action cannot be undone.`,\n\t\t\t\t\tdefault: false,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && error.name === \"ExitPromptError\") {\n\t\t\t\t\tawait cleanup();\n\t\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (!shouldProceed) {\n\t\t\t\tcliLogger.info(\"Rollback cancelled\");\n\t\t\t\tawait cleanup();\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t}\n\n\t\tcliLogger.info(\n\t\t\t`Rolling back ${migrationsToRollback.length} migration(s)...`,\n\t\t);\n\n\t\tlet rolledBackCount = 0;\n\t\tfor (let i = 0; i < migrationsToRollback.length; i++) {\n\t\t\tconst { error, results } = await migrator.migrateDown();\n\n\t\t\tif (results) {\n\t\t\t\tfor (const result of results) {\n\t\t\t\t\tif (result.status === \"Success\") {\n\t\t\t\t\t\tlogger.debug({\n\t\t\t\t\t\t\tmessage: `Rolled back \"${result.migrationName}\" successfully`,\n\t\t\t\t\t\t\tscope: constants.logScopes.migrations,\n\t\t\t\t\t\t});\n\t\t\t\t\t\trolledBackCount++;\n\t\t\t\t\t} else if (result.status === \"Error\") {\n\t\t\t\t\t\tlogger.error({\n\t\t\t\t\t\t\tmessage: `Failed to rollback migration \"${result.migrationName}\"`,\n\t\t\t\t\t\t\tscope: constants.logScopes.migrations,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (error) {\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tcliLogger.errorInstance(error, \"Rollback failed\");\n\t\t\t\t} else {\n\t\t\t\t\tcliLogger.error(\"Rollback failed\", \"Unknown error\");\n\t\t\t\t}\n\t\t\t\tawait cleanup();\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\n\t\tif (rolledBackCount === 0) {\n\t\t\tcliLogger.warn(\"No migrations were rolled back\");\n\t\t} else {\n\t\t\tcliLogger.success(\n\t\t\t\t`Rolled back ${rolledBackCount} migration(s)`,\n\t\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t);\n\t\t}\n\n\t\tcliLogger.info(\"Clearing KV cache...\");\n\t\tkvInstance = await getInitializedKVAdapter(config, {\n\t\t\tenv,\n\t\t\truntimeContext,\n\t\t});\n\t\tawait kvInstance.clear(\n\t\t\tcreateServiceContext({\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\tkv: kvInstance,\n\t\t\t}),\n\t\t);\n\t\tawait cleanup();\n\n\t\tconst endTime = startTime();\n\t\tcliLogger.log(\n\t\t\tcliLogger.createBadge(\"LUCID CMS\"),\n\t\t\t\"Rollback completed\",\n\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\"in\",\n\t\t\tcliLogger.color.green(cliLogger.formatMilliseconds(endTime)),\n\t\t\t{\n\t\t\t\tspaceAfter: true,\n\t\t\t\tspaceBefore: true,\n\t\t\t},\n\t\t);\n\n\t\tawait stopLoggerBuffering();\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tawait cleanup();\n\t\tif (error instanceof Error) {\n\t\t\tcliLogger.errorInstance(error, \"Rollback failed\");\n\t\t} else {\n\t\t\tcliLogger.error(\"Rollback failed\", \"Unknown error\");\n\t\t}\n\t\tawait stopLoggerBuffering();\n\t\tprocess.exit(1);\n\t}\n};\n\nexport default migrateRollbackCommand;\n"],"mappings":"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"}