@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.
@@ -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$1(output) {
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$1(result.stdout) === pin) return candidate;
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
- if (!restored.applied) log("The database already matches supabase/schemas.");
7672
+ log("The database already matches supabase/schemas.");
7684
7673
  return {
7685
7674
  migration: null,
7686
- applied: restored.applied,
7687
- destructive: restored.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: [...restored.destructive, ...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.applied && typesAreCurrent(product)) return;
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.applied) log.success("Your database now matches supabase/schemas.");
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.applied ? "Applied supabase/schemas to your database." : "Your database already matched supabase/schemas.");
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-DV6tvG1E.js");
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.548",
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.",