@supacloud/cli 0.21.1 → 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 -83
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7046,82 +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
|
-
const
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
}
|
|
7082
|
-
|
|
7083
|
-
const conflicts = migrationIdentityConflicts(data, migrationFiles);
|
|
7084
|
-
if (!conflicts.length)
|
|
7085
|
-
return;
|
|
7086
|
-
throw new Error([
|
|
7087
|
-
"Migration identity conflicts:",
|
|
7088
|
-
...conflicts.map(({ file, local, remote }) => `- ${file} (${local.version}) conflicts with remote ${remote.name} (${remote.version})`)
|
|
7089
|
-
].join(`
|
|
7090
|
-
`));
|
|
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;
|
|
7091
7080
|
}
|
|
7092
|
-
function
|
|
7081
|
+
function appliedMigrationKeys(data) {
|
|
7093
7082
|
const keys = new Set;
|
|
7094
|
-
for (const
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
continue;
|
|
7099
|
-
const name = String(row.name);
|
|
7100
|
-
const marker = row.statements[0];
|
|
7101
|
-
if (marker !== `baseline:${name}` && marker !== `direct-apply:${name}`)
|
|
7102
|
-
continue;
|
|
7103
|
-
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);
|
|
7104
7087
|
}
|
|
7105
7088
|
return keys;
|
|
7106
7089
|
}
|
|
7107
|
-
function
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
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);
|
|
7123
7133
|
}
|
|
7124
|
-
return
|
|
7134
|
+
return plan;
|
|
7125
7135
|
}
|
|
7126
7136
|
function isAlreadyAppliedMigrationResponse(response) {
|
|
7127
7137
|
if (response.status !== 409 || !response.data || typeof response.data !== "object")
|
|
@@ -7349,14 +7359,13 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7349
7359
|
const migrationFiles = sortMigrationFiles(files.map((file) => readMigrationFile(dir, file)));
|
|
7350
7360
|
const migrationsResult = await http.get(`/v1/projects/${ref}/database/migrations`);
|
|
7351
7361
|
if (!migrationsResult.ok) {
|
|
7352
|
-
text = `❌ Failed to load applied migrations (${migrationsResult.status})
|
|
7362
|
+
text = `❌ Failed to load applied migrations (${migrationsResult.status})`;
|
|
7353
7363
|
break;
|
|
7354
7364
|
}
|
|
7355
|
-
|
|
7365
|
+
const migrationPlan = migrationPushPlan(migrationsResult.data, migrationFiles);
|
|
7356
7366
|
if (args.dry_run) {
|
|
7357
|
-
const
|
|
7358
|
-
const
|
|
7359
|
-
const alreadyApplied = migrationFiles.filter(({ name, version }) => appliedKeys.has(name) || appliedKeys.has(String(version)));
|
|
7367
|
+
const pending = migrationPlan.pending;
|
|
7368
|
+
const alreadyApplied = migrationPlan.alreadyApplied;
|
|
7360
7369
|
const pendingWithSql = pending;
|
|
7361
7370
|
let vectorEnabled = null;
|
|
7362
7371
|
if (pendingWithSql.some(({ sql }) => sqlReferencesVector(sql) || sqlCreatesVectorExtension(sql))) {
|
|
@@ -7379,15 +7388,8 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7379
7388
|
break;
|
|
7380
7389
|
}
|
|
7381
7390
|
const applied = [];
|
|
7382
|
-
const skipped =
|
|
7383
|
-
const
|
|
7384
|
-
const historicalChecksumKeys = historicalChecksumMarkerKeys(migrationsResult.data, migrationFiles);
|
|
7385
|
-
for (const { file, name, version, sql } of migrationFiles) {
|
|
7386
|
-
const migrationKey = migrationIdentityKey(version, name);
|
|
7387
|
-
if (nameBoundMarkerKeys.has(migrationKey) || historicalChecksumKeys.has(migrationKey)) {
|
|
7388
|
-
skipped.push(file);
|
|
7389
|
-
continue;
|
|
7390
|
-
}
|
|
7391
|
+
const skipped = migrationPlan.alreadyApplied.map(({ file }) => file);
|
|
7392
|
+
for (const { file, name, version, sql } of migrationPlan.pending) {
|
|
7391
7393
|
const r = await http.post(`/v1/projects/${ref}/database/migrations`, { name, sql, version });
|
|
7392
7394
|
if (r.ok) {
|
|
7393
7395
|
applied.push(file);
|
|
@@ -7396,8 +7398,6 @@ Actions: ${allActions.join(", ")}${readOnly ? " (read-only mode)" : ""}`, {
|
|
|
7396
7398
|
} else {
|
|
7397
7399
|
text = [
|
|
7398
7400
|
`❌ Failed to apply ${file} (${r.status})`,
|
|
7399
|
-
JSON.stringify(r.data, null, 2),
|
|
7400
|
-
"",
|
|
7401
7401
|
`Applied before failure: ${applied.length}`,
|
|
7402
7402
|
`Skipped before failure: ${skipped.length}`
|
|
7403
7403
|
].join(`
|
|
@@ -12039,7 +12039,7 @@ var MUTATION_TOOL_SCHEMA = {
|
|
|
12039
12039
|
// package.json
|
|
12040
12040
|
var package_default = {
|
|
12041
12041
|
name: "@supacloud/cli",
|
|
12042
|
-
version: "0.21.
|
|
12042
|
+
version: "0.21.3",
|
|
12043
12043
|
description: "Project-scoped CLI for SupaCloud users",
|
|
12044
12044
|
type: "module",
|
|
12045
12045
|
main: "./dist/index.js",
|