@supacloud/cli 0.21.2 → 0.21.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/index.js +83 -91
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7046,89 +7046,92 @@ function sortMigrationFiles(migrations) {
|
|
|
7046
7046
|
}
|
|
7047
7047
|
return sorted;
|
|
7048
7048
|
}
|
|
7049
|
-
function appliedMigrationKeys(data) {
|
|
7050
|
-
const rows = Array.isArray(data) ? data : data?.rows || [];
|
|
7051
|
-
const keys = new Set;
|
|
7052
|
-
for (const row of rows) {
|
|
7053
|
-
if (!row || typeof row !== "object")
|
|
7054
|
-
continue;
|
|
7055
|
-
const migration = row;
|
|
7056
|
-
if (migration.version != null)
|
|
7057
|
-
keys.add(String(migration.version));
|
|
7058
|
-
if (migration.name != null)
|
|
7059
|
-
keys.add(String(migration.name));
|
|
7060
|
-
}
|
|
7061
|
-
return keys;
|
|
7062
|
-
}
|
|
7063
7049
|
function migrationRows(data) {
|
|
7064
|
-
|
|
7065
|
-
|
|
7050
|
+
if (Array.isArray(data))
|
|
7051
|
+
return data;
|
|
7052
|
+
if (data && typeof data === "object" && Array.isArray(data.rows)) {
|
|
7053
|
+
return data.rows;
|
|
7054
|
+
}
|
|
7055
|
+
throw new Error("Invalid remote migration inventory");
|
|
7066
7056
|
}
|
|
7067
|
-
function
|
|
7068
|
-
|
|
7057
|
+
function migrationIdentity(row) {
|
|
7058
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
7059
|
+
throw new Error("Invalid remote migration identity");
|
|
7060
|
+
}
|
|
7061
|
+
const migration = row;
|
|
7062
|
+
if (!isMigrationInventoryVersion(migration.version) || !isMigrationInventoryName(migration.name)) {
|
|
7063
|
+
throw new Error("Invalid remote migration identity");
|
|
7064
|
+
}
|
|
7065
|
+
return { version: migration.version, name: migration.name, statements: migration.statements };
|
|
7069
7066
|
}
|
|
7070
7067
|
function migrationIdentities(data) {
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
return migrationFiles.flatMap((localMigration) => remoteMigrations.filter((remoteMigration) => identityConflicts(localMigration, remoteMigration, remoteMigrations)).map((remoteMigration) => ({ file: localMigration.file, local: localMigration, remote: remoteMigration })));
|
|
7084
|
-
}
|
|
7085
|
-
function legacyNameBoundMigrationKeys(data, migrationFiles) {
|
|
7086
|
-
const remoteMigrations = migrationIdentities(data);
|
|
7087
|
-
return new Set(migrationFiles.flatMap((localMigration) => remoteMigrations.some((remoteMigration) => isLegacyNameBoundMigration(localMigration, remoteMigration, remoteMigrations)) ? [migrationIdentityKey(localMigration.version, localMigration.name)] : []));
|
|
7088
|
-
}
|
|
7089
|
-
function assertNoMigrationIdentityConflicts(data, migrationFiles) {
|
|
7090
|
-
const conflicts = migrationIdentityConflicts(data, migrationFiles);
|
|
7091
|
-
if (!conflicts.length)
|
|
7092
|
-
return;
|
|
7093
|
-
throw new Error([
|
|
7094
|
-
"Migration identity conflicts:",
|
|
7095
|
-
...conflicts.map(({ file, local, remote }) => `- ${file} (${local.version}) conflicts with remote ${remote.name} (${remote.version})`)
|
|
7096
|
-
].join(`
|
|
7097
|
-
`));
|
|
7068
|
+
const identities = migrationRows(data).map(migrationIdentity);
|
|
7069
|
+
const versions = new Set;
|
|
7070
|
+
const names = new Set;
|
|
7071
|
+
for (const identity of identities) {
|
|
7072
|
+
if (versions.has(identity.version) || identity.name !== null && names.has(identity.name)) {
|
|
7073
|
+
throw new Error("Invalid remote migration inventory");
|
|
7074
|
+
}
|
|
7075
|
+
versions.add(identity.version);
|
|
7076
|
+
if (identity.name !== null)
|
|
7077
|
+
names.add(identity.name);
|
|
7078
|
+
}
|
|
7079
|
+
return identities;
|
|
7098
7080
|
}
|
|
7099
|
-
function
|
|
7081
|
+
function appliedMigrationKeys(data) {
|
|
7100
7082
|
const keys = new Set;
|
|
7101
|
-
for (const
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
continue;
|
|
7106
|
-
const name = String(row.name);
|
|
7107
|
-
const marker = row.statements[0];
|
|
7108
|
-
if (marker !== `baseline:${name}` && marker !== `direct-apply:${name}`)
|
|
7109
|
-
continue;
|
|
7110
|
-
keys.add(migrationIdentityKey(String(row.version), String(row.name)));
|
|
7083
|
+
for (const migration of migrationIdentities(data)) {
|
|
7084
|
+
keys.add(migration.version);
|
|
7085
|
+
if (migration.name !== null)
|
|
7086
|
+
keys.add(migration.name);
|
|
7111
7087
|
}
|
|
7112
7088
|
return keys;
|
|
7113
7089
|
}
|
|
7114
|
-
function
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7090
|
+
function singleRemoteStatement(remote) {
|
|
7091
|
+
return Array.isArray(remote.statements) && remote.statements.length === 1 && typeof remote.statements[0] === "string" ? remote.statements[0] : null;
|
|
7092
|
+
}
|
|
7093
|
+
function exactIdentityIsApplied(local, remote) {
|
|
7094
|
+
const statement = singleRemoteStatement(remote);
|
|
7095
|
+
if (statement === null)
|
|
7096
|
+
return false;
|
|
7097
|
+
if (statement === `baseline:${local.name}` || statement === `direct-apply:${local.name}`)
|
|
7098
|
+
return true;
|
|
7099
|
+
const rawChecksum = createHash("sha256").update(local.rawBytes).digest("hex");
|
|
7100
|
+
return statement === `sha256:${rawChecksum}` || statement.trim() === local.sql.trim();
|
|
7101
|
+
}
|
|
7102
|
+
function legacyIdentityIsApplied(local, remote) {
|
|
7103
|
+
const statement = singleRemoteStatement(remote);
|
|
7104
|
+
return remote.name === local.name && remote.version !== local.version && statement !== null && statement.trim() === local.sql.trim();
|
|
7105
|
+
}
|
|
7106
|
+
function migrationIdentityConflict(local) {
|
|
7107
|
+
return new Error(`Migration identity conflicts:
|
|
7108
|
+
- ${local.file} (${local.version}) conflicts with remote inventory`);
|
|
7109
|
+
}
|
|
7110
|
+
function migrationDisposition(local, remoteMigrations) {
|
|
7111
|
+
const sameVersion = remoteMigrations.filter((remote2) => remote2.version === local.version);
|
|
7112
|
+
const sameName = remoteMigrations.filter((remote2) => remote2.name === local.name);
|
|
7113
|
+
if (sameVersion.length > 1 || sameName.length > 1)
|
|
7114
|
+
throw migrationIdentityConflict(local);
|
|
7115
|
+
if (!sameVersion.length && !sameName.length)
|
|
7116
|
+
return "pending";
|
|
7117
|
+
if (sameVersion[0] && sameName[0] && sameVersion[0] !== sameName[0])
|
|
7118
|
+
throw migrationIdentityConflict(local);
|
|
7119
|
+
const remote = sameVersion[0] ?? sameName[0];
|
|
7120
|
+
const exactIdentity = remote.version === local.version && remote.name === local.name;
|
|
7121
|
+
if (exactIdentity && exactIdentityIsApplied(local, remote))
|
|
7122
|
+
return "applied";
|
|
7123
|
+
if (!sameVersion.length && legacyIdentityIsApplied(local, remote))
|
|
7124
|
+
return "applied";
|
|
7125
|
+
throw migrationIdentityConflict(local);
|
|
7126
|
+
}
|
|
7127
|
+
function migrationPushPlan(data, migrationFiles) {
|
|
7128
|
+
const remoteMigrations = migrationIdentities(data);
|
|
7129
|
+
const plan = { alreadyApplied: [], pending: [] };
|
|
7130
|
+
for (const migration of migrationFiles) {
|
|
7131
|
+
const disposition = migrationDisposition(migration, remoteMigrations);
|
|
7132
|
+
plan[disposition === "applied" ? "alreadyApplied" : "pending"].push(migration);
|
|
7130
7133
|
}
|
|
7131
|
-
return
|
|
7134
|
+
return plan;
|
|
7132
7135
|
}
|
|
7133
7136
|
function isAlreadyAppliedMigrationResponse(response) {
|
|
7134
7137
|
if (response.status !== 409 || !response.data || typeof response.data !== "object")
|
|
@@ -7356,14 +7359,13 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7356
7359
|
const migrationFiles = sortMigrationFiles(files.map((file) => readMigrationFile(dir, file)));
|
|
7357
7360
|
const migrationsResult = await http.get(`/v1/projects/${ref}/database/migrations`);
|
|
7358
7361
|
if (!migrationsResult.ok) {
|
|
7359
|
-
text = `❌ Failed to load applied migrations (${migrationsResult.status})
|
|
7362
|
+
text = `❌ Failed to load applied migrations (${migrationsResult.status})`;
|
|
7360
7363
|
break;
|
|
7361
7364
|
}
|
|
7362
|
-
|
|
7365
|
+
const migrationPlan = migrationPushPlan(migrationsResult.data, migrationFiles);
|
|
7363
7366
|
if (args.dry_run) {
|
|
7364
|
-
const
|
|
7365
|
-
const
|
|
7366
|
-
const alreadyApplied = migrationFiles.filter(({ name, version }) => appliedKeys.has(name) || appliedKeys.has(String(version)));
|
|
7367
|
+
const pending = migrationPlan.pending;
|
|
7368
|
+
const alreadyApplied = migrationPlan.alreadyApplied;
|
|
7367
7369
|
const pendingWithSql = pending;
|
|
7368
7370
|
let vectorEnabled = null;
|
|
7369
7371
|
if (pendingWithSql.some(({ sql }) => sqlReferencesVector(sql) || sqlCreatesVectorExtension(sql))) {
|
|
@@ -7386,16 +7388,8 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7386
7388
|
break;
|
|
7387
7389
|
}
|
|
7388
7390
|
const applied = [];
|
|
7389
|
-
const skipped =
|
|
7390
|
-
const
|
|
7391
|
-
const historicalChecksumKeys = historicalChecksumMarkerKeys(migrationsResult.data, migrationFiles);
|
|
7392
|
-
const legacyNameBoundKeys = legacyNameBoundMigrationKeys(migrationsResult.data, migrationFiles);
|
|
7393
|
-
for (const { file, name, version, sql } of migrationFiles) {
|
|
7394
|
-
const migrationKey = migrationIdentityKey(version, name);
|
|
7395
|
-
if (nameBoundMarkerKeys.has(migrationKey) || historicalChecksumKeys.has(migrationKey) || legacyNameBoundKeys.has(migrationKey)) {
|
|
7396
|
-
skipped.push(file);
|
|
7397
|
-
continue;
|
|
7398
|
-
}
|
|
7391
|
+
const skipped = migrationPlan.alreadyApplied.map(({ file }) => file);
|
|
7392
|
+
for (const { file, name, version, sql } of migrationPlan.pending) {
|
|
7399
7393
|
const r = await http.post(`/v1/projects/${ref}/database/migrations`, { name, sql, version });
|
|
7400
7394
|
if (r.ok) {
|
|
7401
7395
|
applied.push(file);
|
|
@@ -7404,8 +7398,6 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7404
7398
|
} else {
|
|
7405
7399
|
text = [
|
|
7406
7400
|
`❌ Failed to apply ${file} (${r.status})`,
|
|
7407
|
-
JSON.stringify(r.data, null, 2),
|
|
7408
|
-
"",
|
|
7409
7401
|
`Applied before failure: ${applied.length}`,
|
|
7410
7402
|
`Skipped before failure: ${skipped.length}`
|
|
7411
7403
|
].join(`
|
|
@@ -12047,7 +12039,7 @@ var MUTATION_TOOL_SCHEMA = {
|
|
|
12047
12039
|
// package.json
|
|
12048
12040
|
var package_default = {
|
|
12049
12041
|
name: "@supacloud/cli",
|
|
12050
|
-
version: "0.21.
|
|
12042
|
+
version: "0.21.3",
|
|
12051
12043
|
description: "Project-scoped CLI for SupaCloud users",
|
|
12052
12044
|
type: "module",
|
|
12053
12045
|
main: "./dist/index.js",
|