@devdogsuga/devtools 0.1.51-next.548 → 0.1.51-next.549
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-DV6tvG1E.js → cli-Doy2BzCQ.js} +11 -153
- package/dist/launch.js +1 -1
- package/package.json +1 -1
|
@@ -7058,7 +7058,7 @@ function commandLine(command, args) {
|
|
|
7058
7058
|
function cliLine(cli, args) {
|
|
7059
7059
|
return commandLine(cli.command, [...cli.prefix, ...args]);
|
|
7060
7060
|
}
|
|
7061
|
-
function versionOf
|
|
7061
|
+
function versionOf(output) {
|
|
7062
7062
|
return /\b(\d+\.\d+\.\d+)\b/.exec(output)?.[1] ?? null;
|
|
7063
7063
|
}
|
|
7064
7064
|
async function resolveSupabaseCli(root, pin, run, fileExists = existsSync) {
|
|
@@ -7076,7 +7076,7 @@ async function resolveSupabaseCli(root, pin, run, fileExists = existsSync) {
|
|
|
7076
7076
|
});
|
|
7077
7077
|
for (const candidate of candidates) try {
|
|
7078
7078
|
const result = await run(candidate.command, ["--version"], { cwd: root });
|
|
7079
|
-
if (result.code === 0 && versionOf
|
|
7079
|
+
if (result.code === 0 && versionOf(result.stdout) === pin) return candidate;
|
|
7080
7080
|
} catch {}
|
|
7081
7081
|
try {
|
|
7082
7082
|
if ((await run("pnpm", ["--version"], { cwd: root })).code === 0) return {
|
|
@@ -7586,15 +7586,6 @@ function typesAssetName(product, hash) {
|
|
|
7586
7586
|
* Without that, the diff would start from an empty database and write the whole
|
|
7587
7587
|
* schema as one migration, which `db push` rejects as already applied.
|
|
7588
7588
|
*
|
|
7589
|
-
* The record only says what *should* be in the database. Before the diff,
|
|
7590
|
-
* sync therefore compares the database itself with the record (`supabase db
|
|
7591
|
-
* diff --from <database> --to migrations`, restricted to the product's
|
|
7592
|
-
* schemas) and re-applies whatever is missing: a dropped table, a dropped
|
|
7593
|
-
* schema, a database reset behind the record's back. The migration ledger is
|
|
7594
|
-
* never trusted to decide anything; it is rewritten to list the record when it
|
|
7595
|
-
* is missing or short. "The database already matches" is therefore a
|
|
7596
|
-
* statement about the live database.
|
|
7597
|
-
*
|
|
7598
7589
|
* It never resets the database. A reset wipes `auth.custom_oauth_providers`,
|
|
7599
7590
|
* which is where "Sign in with DevDogs" is registered (Q83); `--rebuild` is
|
|
7600
7591
|
* the explicit escape hatch for a database that has drifted from its record,
|
|
@@ -7646,7 +7637,6 @@ async function dbSync(product, cli, target, run, options) {
|
|
|
7646
7637
|
"--db-url",
|
|
7647
7638
|
"<DB_URL>"
|
|
7648
7639
|
])} (this machine has no record of what the project has had applied)`);
|
|
7649
|
-
if (options.open) log(`Would run: ${cliLine(cli, liveDiffArgs(product, target).slice(cli.prefix.length))} (and restore anything the database lost)`);
|
|
7650
7640
|
log(`Would run: ${cliLine(cli, generateArgs.slice(cli.prefix.length))}`);
|
|
7651
7641
|
log(target.kind === "local" ? `Would run: ${cliLine(cli, [
|
|
7652
7642
|
"migration",
|
|
@@ -7670,7 +7660,6 @@ async function dbSync(product, cli, target, run, options) {
|
|
|
7670
7660
|
const restored = migrationFiles(migrationsDir).length;
|
|
7671
7661
|
if (fetched.code === 0 && restored > 0) log(`Restored ${restored} applied migration${restored === 1 ? "" : "s"} from the project's history.`);
|
|
7672
7662
|
}
|
|
7673
|
-
const restored = await restoreDatabase(product, cli, target, run, options, log);
|
|
7674
7663
|
const before = new Set(migrationFiles(migrationsDir));
|
|
7675
7664
|
let generated = await run(cli.command, generateArgs, { cwd: product.root });
|
|
7676
7665
|
if (generated.code !== 0 && isContainerFailure(generated)) {
|
|
@@ -7680,11 +7669,11 @@ async function dbSync(product, cli, target, run, options) {
|
|
|
7680
7669
|
if (generated.code !== 0) throw new SyncError(isContainerFailure(generated) ? "Could not diff the schema: Docker is needed for the shadow database. Start Docker and try again." : "Could not diff the schema against what this database has had applied.", generated.stderr || generated.stdout);
|
|
7681
7670
|
const created = migrationFiles(migrationsDir).filter((f) => !before.has(f));
|
|
7682
7671
|
if (created.length === 0) {
|
|
7683
|
-
|
|
7672
|
+
log("The database already matches supabase/schemas.");
|
|
7684
7673
|
return {
|
|
7685
7674
|
migration: null,
|
|
7686
|
-
applied:
|
|
7687
|
-
destructive:
|
|
7675
|
+
applied: false,
|
|
7676
|
+
destructive: []
|
|
7688
7677
|
};
|
|
7689
7678
|
}
|
|
7690
7679
|
const migration = created[created.length - 1];
|
|
@@ -7718,138 +7707,9 @@ async function dbSync(product, cli, target, run, options) {
|
|
|
7718
7707
|
return {
|
|
7719
7708
|
migration,
|
|
7720
7709
|
applied: true,
|
|
7721
|
-
destructive
|
|
7710
|
+
destructive
|
|
7722
7711
|
};
|
|
7723
7712
|
}
|
|
7724
|
-
/** `20261011120000` from `20261011120000_devtools_sync.sql`. */
|
|
7725
|
-
function versionOf(file) {
|
|
7726
|
-
return file.split("_")[0] ?? file;
|
|
7727
|
-
}
|
|
7728
|
-
function liveDiffArgs(product, target) {
|
|
7729
|
-
return [
|
|
7730
|
-
"db",
|
|
7731
|
-
"diff",
|
|
7732
|
-
"--from",
|
|
7733
|
-
target.kind === "local" ? "local" : target.dbUrl,
|
|
7734
|
-
"--to",
|
|
7735
|
-
"migrations",
|
|
7736
|
-
"--use-pg-delta",
|
|
7737
|
-
"--schema",
|
|
7738
|
-
product.config.supabase.schemas.join(","),
|
|
7739
|
-
"--output-format",
|
|
7740
|
-
"json"
|
|
7741
|
-
];
|
|
7742
|
-
}
|
|
7743
|
-
/**
|
|
7744
|
-
* The SQL that turns the database into what the record describes, from the
|
|
7745
|
-
* CLI's pg-delta diff (database to migrations baseline). Empty when they
|
|
7746
|
-
* agree. Only the product's own schemas are compared, so the platform's
|
|
7747
|
-
* (auth, storage, ...) never show up as drift.
|
|
7748
|
-
*/
|
|
7749
|
-
async function liveDiff(product, cli, target, run, log) {
|
|
7750
|
-
const args = [...cli.prefix, ...liveDiffArgs(product, target)];
|
|
7751
|
-
let result = await run(cli.command, args, { cwd: product.root });
|
|
7752
|
-
if (result.code !== 0 && isContainerFailure(result)) {
|
|
7753
|
-
log("The shadow database did not start; trying once more.");
|
|
7754
|
-
result = await run(cli.command, args, { cwd: product.root });
|
|
7755
|
-
}
|
|
7756
|
-
if (result.code !== 0) throw new SyncError(isContainerFailure(result) ? "Could not compare the database with its record: Docker is needed for the shadow database. Start Docker and try again." : "Could not compare the database with what devtools recorded as applied.", result.stderr || result.stdout);
|
|
7757
|
-
for (const line of result.stdout.split("\n").reverse()) {
|
|
7758
|
-
const text = line.trim();
|
|
7759
|
-
if (!text.startsWith("{")) continue;
|
|
7760
|
-
try {
|
|
7761
|
-
const parsed = JSON.parse(text);
|
|
7762
|
-
if (typeof parsed.diff === "string") return parsed.diff;
|
|
7763
|
-
} catch {}
|
|
7764
|
-
}
|
|
7765
|
-
throw new SyncError("Could not read the result of comparing the database with its record.", result.stdout || result.stderr);
|
|
7766
|
-
}
|
|
7767
|
-
/**
|
|
7768
|
-
* Makes the database agree with the local record, from the database itself.
|
|
7769
|
-
* The declarative diff only compares `supabase/schemas` with
|
|
7770
|
-
* `supabase/migrations`, so a database that lost objects behind the record's
|
|
7771
|
-
* back (a table dropped by hand, a hosted project reset from the dashboard, a
|
|
7772
|
-
* checkout switched from the local stack to a hosted project) would read as
|
|
7773
|
-
* "already matches". So, with a record to compare against:
|
|
7774
|
-
*
|
|
7775
|
-
* 1. the database is diffed against the record, per configured schema, and
|
|
7776
|
-
* whatever it lacks is created again (data in what remains is untouched);
|
|
7777
|
-
* statements that drop something need the same approval as any change;
|
|
7778
|
-
* 2. the migration ledger is made to list every migration in the record
|
|
7779
|
-
* (marking them applied, which they now are), so the next
|
|
7780
|
-
* `migration up` applies only what is new.
|
|
7781
|
-
*
|
|
7782
|
-
* A missing or unreadable ledger decides nothing by itself: it is rewritten,
|
|
7783
|
-
* never read as "start over". A database that cannot be reached is left to
|
|
7784
|
-
* the apply step to report.
|
|
7785
|
-
*/
|
|
7786
|
-
async function restoreDatabase(product, cli, target, run, options, log) {
|
|
7787
|
-
const nothing = {
|
|
7788
|
-
applied: false,
|
|
7789
|
-
destructive: []
|
|
7790
|
-
};
|
|
7791
|
-
const files = migrationFiles(product.paths.migrationsDir);
|
|
7792
|
-
if (!options.open || files.length === 0) return nothing;
|
|
7793
|
-
let session;
|
|
7794
|
-
let missing;
|
|
7795
|
-
let ledger;
|
|
7796
|
-
try {
|
|
7797
|
-
session = options.open(target.dbUrl);
|
|
7798
|
-
missing = await session.missingSchemas(product.config.supabase.schemas);
|
|
7799
|
-
} catch (err) {
|
|
7800
|
-
log(`Could not check what the database has (${err.message}); trusting the local record.`);
|
|
7801
|
-
await session?.close().catch(() => void 0);
|
|
7802
|
-
return nothing;
|
|
7803
|
-
}
|
|
7804
|
-
try {
|
|
7805
|
-
try {
|
|
7806
|
-
ledger = await session.appliedMigrations();
|
|
7807
|
-
} catch (err) {
|
|
7808
|
-
ledger = void 0;
|
|
7809
|
-
log(`Could not read the migration history (${err.message}); deciding from the schemas alone.`);
|
|
7810
|
-
}
|
|
7811
|
-
const sql = (await liveDiff(product, cli, target, run, log)).trim();
|
|
7812
|
-
let applied = false;
|
|
7813
|
-
let destructive = [];
|
|
7814
|
-
if (sql) {
|
|
7815
|
-
destructive = destructiveStatements(sql);
|
|
7816
|
-
if (destructive.length > 0 && !options.yes) {
|
|
7817
|
-
if (!(options.confirmDestructive ? await options.confirmDestructive(sql, destructive) : false)) throw new SyncError(`The database differs from supabase/schemas and putting it right drops data in your development database (${destructive.length} statement${destructive.length === 1 ? "" : "s"}). Re-run with --yes to allow it.`, destructive.join(";\n"));
|
|
7818
|
-
}
|
|
7819
|
-
log(missing.length > 0 ? `The database is missing ${missing.length === 1 ? "schema" : "schemas"} ${missing.join(", ")}; creating ${missing.length === 1 ? "it" : "them"} again from supabase/schemas.` : "The database has lost part of supabase/schemas (a dropped table, view or function, perhaps); restoring it. Existing data is kept.");
|
|
7820
|
-
try {
|
|
7821
|
-
await session.exec(sql);
|
|
7822
|
-
} catch (err) {
|
|
7823
|
-
throw new SyncError("Could not restore what the database lost. `devtools db sync --rebuild` starts over (it wipes local data).", err.message);
|
|
7824
|
-
}
|
|
7825
|
-
applied = true;
|
|
7826
|
-
}
|
|
7827
|
-
if (ledger !== void 0) {
|
|
7828
|
-
const known = new Set(ledger ?? []);
|
|
7829
|
-
const unlisted = files.map(versionOf).filter((version) => !known.has(version));
|
|
7830
|
-
if (unlisted.length > 0) {
|
|
7831
|
-
if (ledger === null) log("The database has no migration history table; recreating it from the local record.");
|
|
7832
|
-
const repaired = await run(cli.command, [
|
|
7833
|
-
...cli.prefix,
|
|
7834
|
-
"migration",
|
|
7835
|
-
"repair",
|
|
7836
|
-
"--status",
|
|
7837
|
-
"applied",
|
|
7838
|
-
"--db-url",
|
|
7839
|
-
target.dbUrl,
|
|
7840
|
-
...unlisted
|
|
7841
|
-
], { cwd: product.root });
|
|
7842
|
-
if (repaired.code !== 0) throw new SyncError("Could not record the applied migrations in the database's history.", repaired.stderr || repaired.stdout);
|
|
7843
|
-
}
|
|
7844
|
-
}
|
|
7845
|
-
return {
|
|
7846
|
-
applied,
|
|
7847
|
-
destructive
|
|
7848
|
-
};
|
|
7849
|
-
} finally {
|
|
7850
|
-
await session.close().catch(() => void 0);
|
|
7851
|
-
}
|
|
7852
|
-
}
|
|
7853
7713
|
function isContainerFailure(result) {
|
|
7854
7714
|
return /docker|container|image/i.test(result.stderr + result.stdout);
|
|
7855
7715
|
}
|
|
@@ -8112,8 +7972,7 @@ async function runSync(product, deps, rest) {
|
|
|
8112
7972
|
yes: hasYes(rest),
|
|
8113
7973
|
confirmDestructive: deps.interactive() ? confirmDestructive : void 0,
|
|
8114
7974
|
dryRun,
|
|
8115
|
-
log: (line) => log.info(line)
|
|
8116
|
-
open: deps.openSql
|
|
7975
|
+
log: (line) => log.info(line)
|
|
8117
7976
|
});
|
|
8118
7977
|
if (rest.includes("--rebuild") && !dryRun) try {
|
|
8119
7978
|
const row = await reRegisterSavedProvider(product.paths.toolingFile, target);
|
|
@@ -8138,7 +7997,7 @@ async function regenerateAfterSync(product, cli, target, result, deps) {
|
|
|
8138
7997
|
log.info(`Would regenerate ${product.config.types.out}.`);
|
|
8139
7998
|
return;
|
|
8140
7999
|
}
|
|
8141
|
-
if (!result.
|
|
8000
|
+
if (!result.migration && typesAreCurrent(product)) return;
|
|
8142
8001
|
try {
|
|
8143
8002
|
await generateTypes(product, cli, target, deps.run, (line) => log.info(line));
|
|
8144
8003
|
log.success(`Regenerated ${product.config.types.out}.`);
|
|
@@ -8184,7 +8043,7 @@ function createProductHandlers(deps = defaultDeps) {
|
|
|
8184
8043
|
switch (sub) {
|
|
8185
8044
|
case "sync": {
|
|
8186
8045
|
const { result, cli, target } = await runSync(product, deps, flags);
|
|
8187
|
-
if (result.
|
|
8046
|
+
if (result.migration) log.success("Your database now matches supabase/schemas.");
|
|
8188
8047
|
await regenerateAfterSync(product, cli, target, result, deps);
|
|
8189
8048
|
return DONE;
|
|
8190
8049
|
}
|
|
@@ -8414,10 +8273,9 @@ async function runSetup(product, deps, rest) {
|
|
|
8414
8273
|
const result = await dbSync(product, cli, target, deps.run, {
|
|
8415
8274
|
yes: hasYes(rest),
|
|
8416
8275
|
confirmDestructive: deps.interactive() ? confirmDestructive : void 0,
|
|
8417
|
-
log: (line) => log.info(line)
|
|
8418
|
-
open: deps.openSql
|
|
8276
|
+
log: (line) => log.info(line)
|
|
8419
8277
|
});
|
|
8420
|
-
log.success(result.
|
|
8278
|
+
log.success(result.migration ? "Applied supabase/schemas to your database." : "Your database already matched supabase/schemas.");
|
|
8421
8279
|
if (target.kind === "local") await waitForRest(target, deps, product);
|
|
8422
8280
|
if (rest.includes("--download-types")) try {
|
|
8423
8281
|
await downloadTypes(product, {
|
package/dist/launch.js
CHANGED
|
@@ -183,7 +183,7 @@ async function startStack() {
|
|
|
183
183
|
* post-tier-resolution path.
|
|
184
184
|
*/
|
|
185
185
|
async function dispatch(argv) {
|
|
186
|
-
const { main } = await import("./cli-
|
|
186
|
+
const { main } = await import("./cli-Doy2BzCQ.js");
|
|
187
187
|
try {
|
|
188
188
|
await main(argv);
|
|
189
189
|
} catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devdogsuga/devtools",
|
|
3
|
-
"version": "0.1.51-next.
|
|
3
|
+
"version": "0.1.51-next.549",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Contributor CLI for DevDogs repositories (the platform monorepo, DogDays, DogPack): the real tools with the session's tier filled in, `setup`, `db sync`, `db types`, `dev-data`, a menu over them, the checks CI runs, and the `with-env` launcher. Ships built JS; run via `pnpm devtools` in a product repo, `pnpm dlx @devdogsuga/devtools` (or the `devtools` bin once installed) from inside a clone.",
|