arkormx 2.0.0-next.2 → 2.0.0-next.3
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/cli.mjs +164 -28
- package/dist/index.cjs +398 -29
- package/dist/index.d.cts +148 -96
- package/dist/index.d.mts +148 -96
- package/dist/index.mjs +387 -29
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1371,6 +1371,28 @@ const getMigrationPlan = async (migration, direction = "up") => {
|
|
|
1371
1371
|
else await instance.down(schema);
|
|
1372
1372
|
return schema.getOperations();
|
|
1373
1373
|
};
|
|
1374
|
+
const supportsDatabaseMigrationExecution = (adapter) => {
|
|
1375
|
+
return typeof adapter?.executeSchemaOperations === "function";
|
|
1376
|
+
};
|
|
1377
|
+
const supportsDatabaseReset = (adapter) => {
|
|
1378
|
+
return typeof adapter?.resetDatabase === "function";
|
|
1379
|
+
};
|
|
1380
|
+
const stripPrismaSchemaModelsAndEnums = (schema) => {
|
|
1381
|
+
const stripped = schema.replace(PRISMA_MODEL_REGEX, "").replace(PRISMA_ENUM_REGEX, "").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
1382
|
+
return stripped.length > 0 ? `${stripped}\n` : "";
|
|
1383
|
+
};
|
|
1384
|
+
const applyMigrationToDatabase = async (adapter, migration) => {
|
|
1385
|
+
if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
|
|
1386
|
+
const operations = await getMigrationPlan(migration, "up");
|
|
1387
|
+
await adapter.executeSchemaOperations(operations);
|
|
1388
|
+
return { operations };
|
|
1389
|
+
};
|
|
1390
|
+
const applyMigrationRollbackToDatabase = async (adapter, migration) => {
|
|
1391
|
+
if (!supportsDatabaseMigrationExecution(adapter)) throw new ArkormException("The configured adapter does not support database-backed migration execution.");
|
|
1392
|
+
const operations = await getMigrationPlan(migration, "down");
|
|
1393
|
+
await adapter.executeSchemaOperations(operations);
|
|
1394
|
+
return { operations };
|
|
1395
|
+
};
|
|
1374
1396
|
/**
|
|
1375
1397
|
* Apply the schema operations defined in a migration to a Prisma schema
|
|
1376
1398
|
* file, updating the file on disk if specified, and return the updated
|
|
@@ -2509,10 +2531,13 @@ var MakeSeederCommand = class extends Command {
|
|
|
2509
2531
|
|
|
2510
2532
|
//#endregion
|
|
2511
2533
|
//#region src/helpers/migration-history.ts
|
|
2512
|
-
const
|
|
2534
|
+
const createEmptyAppliedMigrationsState = () => ({
|
|
2513
2535
|
version: 1,
|
|
2514
2536
|
migrations: [],
|
|
2515
2537
|
runs: []
|
|
2538
|
+
});
|
|
2539
|
+
const supportsDatabaseMigrationState = (adapter) => {
|
|
2540
|
+
return typeof adapter?.readAppliedMigrationsState === "function" && typeof adapter?.writeAppliedMigrationsState === "function";
|
|
2516
2541
|
};
|
|
2517
2542
|
const resolveMigrationStateFilePath = (cwd, configuredPath) => {
|
|
2518
2543
|
if (configuredPath && configuredPath.trim().length > 0) return resolve(configuredPath);
|
|
@@ -2527,10 +2552,10 @@ const computeMigrationChecksum = (filePath) => {
|
|
|
2527
2552
|
return createHash("sha256").update(source).digest("hex");
|
|
2528
2553
|
};
|
|
2529
2554
|
const readAppliedMigrationsState = (stateFilePath) => {
|
|
2530
|
-
if (!existsSync(stateFilePath)) return
|
|
2555
|
+
if (!existsSync(stateFilePath)) return createEmptyAppliedMigrationsState();
|
|
2531
2556
|
try {
|
|
2532
2557
|
const parsed = JSON.parse(readFileSync(stateFilePath, "utf-8"));
|
|
2533
|
-
if (!Array.isArray(parsed.migrations)) return
|
|
2558
|
+
if (!Array.isArray(parsed.migrations)) return createEmptyAppliedMigrationsState();
|
|
2534
2559
|
return {
|
|
2535
2560
|
version: 1,
|
|
2536
2561
|
migrations: parsed.migrations.filter((migration) => {
|
|
@@ -2541,14 +2566,25 @@ const readAppliedMigrationsState = (stateFilePath) => {
|
|
|
2541
2566
|
}) : []
|
|
2542
2567
|
};
|
|
2543
2568
|
} catch {
|
|
2544
|
-
return
|
|
2569
|
+
return createEmptyAppliedMigrationsState();
|
|
2545
2570
|
}
|
|
2546
2571
|
};
|
|
2572
|
+
const readAppliedMigrationsStateFromStore = async (adapter, stateFilePath) => {
|
|
2573
|
+
if (supportsDatabaseMigrationState(adapter)) return await adapter.readAppliedMigrationsState();
|
|
2574
|
+
return readAppliedMigrationsState(stateFilePath);
|
|
2575
|
+
};
|
|
2547
2576
|
const writeAppliedMigrationsState = (stateFilePath, state) => {
|
|
2548
2577
|
const directory = dirname(stateFilePath);
|
|
2549
2578
|
if (!existsSync(directory)) mkdirSync(directory, { recursive: true });
|
|
2550
2579
|
writeFileSync(stateFilePath, JSON.stringify(state, null, 2));
|
|
2551
2580
|
};
|
|
2581
|
+
const writeAppliedMigrationsStateToStore = async (adapter, stateFilePath, state) => {
|
|
2582
|
+
if (supportsDatabaseMigrationState(adapter)) {
|
|
2583
|
+
await adapter.writeAppliedMigrationsState(state);
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
writeAppliedMigrationsState(stateFilePath, state);
|
|
2587
|
+
};
|
|
2552
2588
|
const isMigrationApplied = (state, identity, checksum) => {
|
|
2553
2589
|
const matched = state.migrations.find((migration) => migration.id === identity);
|
|
2554
2590
|
if (!matched) return false;
|
|
@@ -2667,7 +2703,9 @@ var MigrateCommand = class extends Command {
|
|
|
2667
2703
|
const classes = this.option("all") || !this.argument("name") ? await this.loadAllMigrations(migrationsDir) : (await this.loadNamedMigration(migrationsDir, this.argument("name"))).filter(([cls]) => cls !== void 0);
|
|
2668
2704
|
if (classes.length === 0) return void this.error("Error: No migration classes found to run.");
|
|
2669
2705
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
2670
|
-
let appliedState =
|
|
2706
|
+
let appliedState = await readAppliedMigrationsStateFromStore(this.app.getConfig("adapter"), stateFilePath);
|
|
2707
|
+
const adapter = this.app.getConfig("adapter");
|
|
2708
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
2671
2709
|
const skipped = [];
|
|
2672
2710
|
const changed = [];
|
|
2673
2711
|
const pending = classes.filter(([migrationClass, file]) => {
|
|
@@ -2689,10 +2727,16 @@ var MigrateCommand = class extends Command {
|
|
|
2689
2727
|
this.success("No pending migration classes to apply.");
|
|
2690
2728
|
return;
|
|
2691
2729
|
}
|
|
2692
|
-
for (const [MigrationClassItem] of pending)
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2730
|
+
for (const [MigrationClassItem] of pending) {
|
|
2731
|
+
if (useDatabaseMigrations) {
|
|
2732
|
+
await applyMigrationToDatabase(adapter, MigrationClassItem);
|
|
2733
|
+
continue;
|
|
2734
|
+
}
|
|
2735
|
+
await applyMigrationToPrismaSchema(MigrationClassItem, {
|
|
2736
|
+
schemaPath,
|
|
2737
|
+
write: true
|
|
2738
|
+
});
|
|
2739
|
+
}
|
|
2696
2740
|
if (appliedState) {
|
|
2697
2741
|
const runAppliedIds = [];
|
|
2698
2742
|
for (const [migrationClass, file] of pending) {
|
|
@@ -2711,10 +2755,10 @@ var MigrateCommand = class extends Command {
|
|
|
2711
2755
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2712
2756
|
migrationIds: runAppliedIds
|
|
2713
2757
|
});
|
|
2714
|
-
|
|
2758
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
2715
2759
|
}
|
|
2716
|
-
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
2717
|
-
if (!this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
2760
|
+
if (!useDatabaseMigrations && !this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
2761
|
+
if (!useDatabaseMigrations && !this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
2718
2762
|
else runPrismaCommand([
|
|
2719
2763
|
"migrate",
|
|
2720
2764
|
"dev",
|
|
@@ -2774,6 +2818,85 @@ var MigrateCommand = class extends Command {
|
|
|
2774
2818
|
}
|
|
2775
2819
|
};
|
|
2776
2820
|
|
|
2821
|
+
//#endregion
|
|
2822
|
+
//#region src/cli/commands/MigrateFreshCommand.ts
|
|
2823
|
+
var MigrateFreshCommand = class extends Command {
|
|
2824
|
+
signature = `migrate:fresh
|
|
2825
|
+
{--skip-generate : Skip prisma generate}
|
|
2826
|
+
{--skip-migrate : Skip prisma database sync}
|
|
2827
|
+
{--state-file= : Path to applied migration state file}
|
|
2828
|
+
{--schema= : Explicit prisma schema path}
|
|
2829
|
+
`;
|
|
2830
|
+
description = "Reset the database and rerun all migration classes";
|
|
2831
|
+
async handle() {
|
|
2832
|
+
this.app.command = this;
|
|
2833
|
+
const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
|
|
2834
|
+
const migrationsDir = this.app.resolveRuntimeDirectoryPath(configuredMigrationsDir);
|
|
2835
|
+
if (!existsSync(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
2836
|
+
const adapter = this.app.getConfig("adapter");
|
|
2837
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
2838
|
+
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
2839
|
+
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
2840
|
+
const migrations = await this.loadAllMigrations(migrationsDir);
|
|
2841
|
+
if (migrations.length === 0) return void this.error("Error: No migration classes found to run.");
|
|
2842
|
+
if (supportsDatabaseReset(adapter)) await adapter.resetDatabase();
|
|
2843
|
+
else {
|
|
2844
|
+
if (!existsSync(schemaPath)) return void this.error(`Error: Prisma schema file not found: ${this.app.formatPathForLog(schemaPath)}`);
|
|
2845
|
+
writeFileSync(schemaPath, stripPrismaSchemaModelsAndEnums(readFileSync(schemaPath, "utf-8")));
|
|
2846
|
+
}
|
|
2847
|
+
let appliedState = createEmptyAppliedMigrationsState();
|
|
2848
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
2849
|
+
for (const [MigrationClassItem] of migrations) {
|
|
2850
|
+
if (useDatabaseMigrations) {
|
|
2851
|
+
await applyMigrationToDatabase(adapter, MigrationClassItem);
|
|
2852
|
+
continue;
|
|
2853
|
+
}
|
|
2854
|
+
await applyMigrationToPrismaSchema(MigrationClassItem, {
|
|
2855
|
+
schemaPath,
|
|
2856
|
+
write: true
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
for (const [migrationClass, file] of migrations) appliedState = markMigrationApplied(appliedState, {
|
|
2860
|
+
id: buildMigrationIdentity(file, migrationClass.name),
|
|
2861
|
+
file,
|
|
2862
|
+
className: migrationClass.name,
|
|
2863
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2864
|
+
checksum: computeMigrationChecksum(file)
|
|
2865
|
+
});
|
|
2866
|
+
appliedState = markMigrationRun(appliedState, {
|
|
2867
|
+
id: buildMigrationRunId(),
|
|
2868
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2869
|
+
migrationIds: appliedState.migrations.map((migration) => migration.id)
|
|
2870
|
+
});
|
|
2871
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
2872
|
+
if (!useDatabaseMigrations) {
|
|
2873
|
+
const schemaArgs = this.option("schema") ? ["--schema", schemaPath] : [];
|
|
2874
|
+
if (!this.option("skip-generate")) runPrismaCommand(["generate", ...schemaArgs], process.cwd());
|
|
2875
|
+
if (!this.option("skip-migrate")) runPrismaCommand([
|
|
2876
|
+
"db",
|
|
2877
|
+
"push",
|
|
2878
|
+
"--force-reset",
|
|
2879
|
+
...schemaArgs
|
|
2880
|
+
], process.cwd());
|
|
2881
|
+
}
|
|
2882
|
+
this.success(`Refreshed database with ${migrations.length} migration(s).`);
|
|
2883
|
+
migrations.forEach(([_, file]) => this.success(this.app.splitLogger("Migrated", file)));
|
|
2884
|
+
}
|
|
2885
|
+
async loadAllMigrations(migrationsDir) {
|
|
2886
|
+
const files = readdirSync(migrationsDir).filter((file) => /\.(ts|js|mjs|cjs)$/i.test(file)).sort((left, right) => left.localeCompare(right)).map((file) => this.app.resolveRuntimeScriptPath(join(migrationsDir, file)));
|
|
2887
|
+
return (await Promise.all(files.map(async (file) => (await this.loadMigrationClassesFromFile(file)).map((cls) => [cls, file])))).flat();
|
|
2888
|
+
}
|
|
2889
|
+
async loadMigrationClassesFromFile(filePath) {
|
|
2890
|
+
const imported = await RuntimeModuleLoader.load(filePath);
|
|
2891
|
+
return Object.values(imported).filter((value) => {
|
|
2892
|
+
if (typeof value !== "function") return false;
|
|
2893
|
+
const candidate = value;
|
|
2894
|
+
const prototype = candidate.prototype;
|
|
2895
|
+
return candidate[MIGRATION_BRAND] === true || typeof prototype?.up === "function" && typeof prototype?.down === "function";
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
};
|
|
2899
|
+
|
|
2777
2900
|
//#endregion
|
|
2778
2901
|
//#region src/cli/commands/MigrateRollbackCommand.ts
|
|
2779
2902
|
/**
|
|
@@ -2802,7 +2925,9 @@ var MigrateRollbackCommand = class extends Command {
|
|
|
2802
2925
|
if (!existsSync(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
2803
2926
|
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
2804
2927
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
2805
|
-
|
|
2928
|
+
const adapter = this.app.getConfig("adapter");
|
|
2929
|
+
const useDatabaseMigrations = supportsDatabaseMigrationExecution(adapter);
|
|
2930
|
+
let appliedState = await readAppliedMigrationsStateFromStore(adapter, stateFilePath);
|
|
2806
2931
|
const stepOption = this.option("step");
|
|
2807
2932
|
const stepCount = stepOption == null ? void 0 : Number(stepOption);
|
|
2808
2933
|
if (stepCount != null && (!Number.isFinite(stepCount) || stepCount <= 0 || !Number.isInteger(stepCount))) return void this.error("Error: --step must be a positive integer.");
|
|
@@ -2824,17 +2949,23 @@ var MigrateRollbackCommand = class extends Command {
|
|
|
2824
2949
|
rollbackClasses.forEach(([_, file]) => this.success(this.app.splitLogger("WouldRollback", file)));
|
|
2825
2950
|
return;
|
|
2826
2951
|
}
|
|
2827
|
-
for (const [MigrationClassItem] of rollbackClasses)
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2952
|
+
for (const [MigrationClassItem] of rollbackClasses) {
|
|
2953
|
+
if (useDatabaseMigrations) {
|
|
2954
|
+
await applyMigrationRollbackToDatabase(adapter, MigrationClassItem);
|
|
2955
|
+
continue;
|
|
2956
|
+
}
|
|
2957
|
+
await applyMigrationRollbackToPrismaSchema(MigrationClassItem, {
|
|
2958
|
+
schemaPath,
|
|
2959
|
+
write: true
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2831
2962
|
for (const [migrationClass, file] of rollbackClasses) {
|
|
2832
2963
|
const identity = buildMigrationIdentity(file, migrationClass.name);
|
|
2833
2964
|
appliedState = removeAppliedMigration(appliedState, identity);
|
|
2834
2965
|
}
|
|
2835
|
-
|
|
2836
|
-
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
2837
|
-
if (!this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
2966
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, appliedState);
|
|
2967
|
+
if (!useDatabaseMigrations && !this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
2968
|
+
if (!useDatabaseMigrations && !this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
2838
2969
|
else runPrismaCommand([
|
|
2839
2970
|
"migrate",
|
|
2840
2971
|
"dev",
|
|
@@ -2878,7 +3009,14 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
2878
3009
|
async handle() {
|
|
2879
3010
|
this.app.command = this;
|
|
2880
3011
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
3012
|
+
const adapter = this.app.getConfig("adapter");
|
|
3013
|
+
const usesDatabaseState = supportsDatabaseMigrationState(adapter);
|
|
2881
3014
|
if (this.option("delete")) {
|
|
3015
|
+
if (usesDatabaseState) {
|
|
3016
|
+
await adapter.writeAppliedMigrationsState(createEmptyAppliedMigrationsState());
|
|
3017
|
+
this.success("Deleted tracked migration state from database.");
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
2882
3020
|
if (!existsSync(stateFilePath)) {
|
|
2883
3021
|
this.success(`No migration state file found at ${this.app.formatPathForLog(stateFilePath)}`);
|
|
2884
3022
|
return;
|
|
@@ -2888,22 +3026,19 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
2888
3026
|
return;
|
|
2889
3027
|
}
|
|
2890
3028
|
if (this.option("reset")) {
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
migrations: []
|
|
2894
|
-
});
|
|
2895
|
-
this.success(`Reset migration state: ${this.app.formatPathForLog(stateFilePath)}`);
|
|
3029
|
+
await writeAppliedMigrationsStateToStore(adapter, stateFilePath, createEmptyAppliedMigrationsState());
|
|
3030
|
+
this.success(usesDatabaseState ? "Reset migration state in database." : `Reset migration state: ${this.app.formatPathForLog(stateFilePath)}`);
|
|
2896
3031
|
return;
|
|
2897
3032
|
}
|
|
2898
|
-
const state =
|
|
3033
|
+
const state = await readAppliedMigrationsStateFromStore(adapter, stateFilePath);
|
|
2899
3034
|
if (this.option("json")) {
|
|
2900
3035
|
this.success(JSON.stringify({
|
|
2901
|
-
path: stateFilePath,
|
|
3036
|
+
path: usesDatabaseState ? "database" : stateFilePath,
|
|
2902
3037
|
...state
|
|
2903
3038
|
}, null, 2));
|
|
2904
3039
|
return;
|
|
2905
3040
|
}
|
|
2906
|
-
this.success(this.app.splitLogger("State", stateFilePath));
|
|
3041
|
+
this.success(this.app.splitLogger("State", usesDatabaseState ? "database" : stateFilePath));
|
|
2907
3042
|
this.success(this.app.splitLogger("Tracked", String(state.migrations.length)));
|
|
2908
3043
|
if (state.migrations.length === 0) {
|
|
2909
3044
|
this.success("No tracked migrations found.");
|
|
@@ -3096,6 +3231,7 @@ await Kernel.init(app, {
|
|
|
3096
3231
|
ModelsSyncCommand,
|
|
3097
3232
|
SeedCommand,
|
|
3098
3233
|
MigrateCommand,
|
|
3234
|
+
MigrateFreshCommand,
|
|
3099
3235
|
MigrateRollbackCommand,
|
|
3100
3236
|
MigrationHistoryCommand
|
|
3101
3237
|
],
|