@rebasepro/server-postgres 0.25.1 → 0.26.0

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.
Files changed (83) hide show
  1. package/dist/{BranchService-ClklxyAQ.js → BranchService-CWBnDhcv.js} +25 -9
  2. package/dist/BranchService-CWBnDhcv.js.map +1 -0
  3. package/dist/PostgresBackendDriver.d.ts +13 -0
  4. package/dist/PostgresBootstrapper.d.ts +7 -0
  5. package/dist/auth/services.d.ts +8 -1
  6. package/dist/auth/verify-auth-tables.d.ts +21 -0
  7. package/dist/{backup-cli-gijeXe0u.js → backup-cli-PoRG-zEq.js} +3 -3
  8. package/dist/{backup-cli-gijeXe0u.js.map → backup-cli-PoRG-zEq.js.map} +1 -1
  9. package/dist/{boot-ddl-DYH95Qeg.js → boot-ddl-EsgqDkx0.js} +2 -2
  10. package/dist/{boot-ddl-DYH95Qeg.js.map → boot-ddl-EsgqDkx0.js.map} +1 -1
  11. package/dist/branch-diff-CxE4VlxT.js +1396 -0
  12. package/dist/branch-diff-CxE4VlxT.js.map +1 -0
  13. package/dist/branch-diff-report-DpvVf7hR.js +48 -0
  14. package/dist/branch-diff-report-DpvVf7hR.js.map +1 -0
  15. package/dist/branching/branch-diff-report.d.ts +7 -0
  16. package/dist/branching/branch-diff.d.ts +115 -0
  17. package/dist/{cli-console-CQrQ0lAY.js → cli-console-f0k6_TsJ.js} +38 -5
  18. package/dist/cli-console-f0k6_TsJ.js.map +1 -0
  19. package/dist/cli-console.d.ts +17 -1
  20. package/dist/{cli-errors-DiA0XFIS.js → cli-errors-DsYyNYzd.js} +53 -2
  21. package/dist/cli-errors-DsYyNYzd.js.map +1 -0
  22. package/dist/cli.js +102 -122
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{collections-schema-version-T6cGvrDi.js → collections-schema-version-D7bDI0PJ.js} +13 -9
  25. package/dist/collections-schema-version-D7bDI0PJ.js.map +1 -0
  26. package/dist/{deferred-index-build-BE0I6sYU.js → deferred-index-build-CqaOv1Xx.js} +3 -3
  27. package/dist/{deferred-index-build-BE0I6sYU.js.map → deferred-index-build-CqaOv1Xx.js.map} +1 -1
  28. package/dist/{doctor-BT--1kq3.js → doctor-DW_mlTzz.js} +81 -33
  29. package/dist/doctor-DW_mlTzz.js.map +1 -0
  30. package/dist/{ensure-collection-policies-BnGOURpG.js → ensure-collection-policies-DLWgabQ2.js} +5 -5
  31. package/dist/{ensure-collection-policies-BnGOURpG.js.map → ensure-collection-policies-DLWgabQ2.js.map} +1 -1
  32. package/dist/{ensure-collection-tables-Cet4650m.js → ensure-collection-tables-CFIRq8ni.js} +5 -5
  33. package/dist/{ensure-collection-tables-Cet4650m.js.map → ensure-collection-tables-CFIRq8ni.js.map} +1 -1
  34. package/dist/{ensure-tables-l_OgFQjN.js → ensure-tables-4nA-tfwi.js} +4 -4
  35. package/dist/{ensure-tables-l_OgFQjN.js.map → ensure-tables-4nA-tfwi.js.map} +1 -1
  36. package/dist/{enum-labels-kept-nheku1pB.js → enum-labels-kept-PcPW65xy.js} +2 -2
  37. package/dist/{enum-labels-kept-nheku1pB.js.map → enum-labels-kept-PcPW65xy.js.map} +1 -1
  38. package/dist/history/HistoryService.d.ts +7 -0
  39. package/dist/index.d.ts +20 -0
  40. package/dist/index.es.js +226 -8
  41. package/dist/index.es.js.map +1 -1
  42. package/dist/{db-subcommands-BPoHCxJR.js → migrate-baseline-B-2Ef4Mv.js} +266 -41
  43. package/dist/migrate-baseline-B-2Ef4Mv.js.map +1 -0
  44. package/dist/{migrate-policy-stamps-3eqfhes6.js → migrate-policy-stamps-BQtFHApx.js} +5 -5
  45. package/dist/{migrate-policy-stamps-3eqfhes6.js.map → migrate-policy-stamps-BQtFHApx.js.map} +1 -1
  46. package/dist/{open-rebase-EmqVmS14.js → open-rebase-C8jQ6s5a.js} +292 -46
  47. package/dist/open-rebase-C8jQ6s5a.js.map +1 -0
  48. package/dist/open-rebase.d.ts +9 -1
  49. package/dist/{pg-error-utils-CFEnm2m9.js → pg-error-utils-DhiUTlVx.js} +2 -2
  50. package/dist/{pg-error-utils-CFEnm2m9.js.map → pg-error-utils-DhiUTlVx.js.map} +1 -1
  51. package/dist/{push-index-prebuild-COd7i6wm.js → push-index-prebuild-UTvB5pqH.js} +3 -3
  52. package/dist/{push-index-prebuild-COd7i6wm.js.map → push-index-prebuild-UTvB5pqH.js.map} +1 -1
  53. package/dist/push-kept-defaults-BGOlOqRQ.js +137 -0
  54. package/dist/push-kept-defaults-BGOlOqRQ.js.map +1 -0
  55. package/dist/{push-legacy-renames-CLgYYwPE.js → push-legacy-renames-BwaKi8xF.js} +3 -3
  56. package/dist/{push-legacy-renames-CLgYYwPE.js.map → push-legacy-renames-BwaKi8xF.js.map} +1 -1
  57. package/dist/{push-policy-plan-D2gpQsdv.js → push-policy-plan-DQ2tWceD.js} +2 -2
  58. package/dist/{push-policy-plan-D2gpQsdv.js.map → push-policy-plan-DQ2tWceD.js.map} +1 -1
  59. package/dist/{rls-enforcement-DDyNoOSy.js → rls-enforcement-BOHuHVlc.js} +42 -3
  60. package/dist/rls-enforcement-BOHuHVlc.js.map +1 -0
  61. package/dist/schema/destructive-sql.d.ts +16 -0
  62. package/dist/schema/doctor-cli.js +3 -3
  63. package/dist/schema/introspect-db.js +1 -1
  64. package/dist/schema/migration-freshness.d.ts +69 -0
  65. package/dist/schema/push-kept-defaults.d.ts +57 -0
  66. package/dist/schema/rls-bootstrap-sql.d.ts +47 -10
  67. package/dist/security/rls-enforcement.d.ts +18 -0
  68. package/dist/services/FetchService.d.ts +12 -0
  69. package/dist/services/channel-presence.d.ts +3 -1
  70. package/dist/services/nested-path.d.ts +16 -0
  71. package/dist/services/realtimeService.d.ts +18 -1
  72. package/dist/{websocket-BKZwsjmf.js → websocket-CKYc3V4N.js} +41 -12
  73. package/dist/websocket-CKYc3V4N.js.map +1 -0
  74. package/package.json +7 -7
  75. package/dist/BranchService-ClklxyAQ.js.map +0 -1
  76. package/dist/cli-console-CQrQ0lAY.js.map +0 -1
  77. package/dist/cli-errors-DiA0XFIS.js.map +0 -1
  78. package/dist/collections-schema-version-T6cGvrDi.js.map +0 -1
  79. package/dist/db-subcommands-BPoHCxJR.js.map +0 -1
  80. package/dist/doctor-BT--1kq3.js.map +0 -1
  81. package/dist/open-rebase-EmqVmS14.js.map +0 -1
  82. package/dist/rls-enforcement-DDyNoOSy.js.map +0 -1
  83. package/dist/websocket-BKZwsjmf.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  __createRequire(import.meta.url);
3
3
  import { a as __require, i as __exportAll, n as require_arg, o as __toESM, r as __commonJSMin } from "./cli-prompt-DXG0yk-h.js";
4
- import { et as redactConnectionPasswords } from "./cli-errors-DiA0XFIS.js";
4
+ import { B as withAppClient, tt as redactConnectionPasswords } from "./cli-errors-DsYyNYzd.js";
5
5
  import { LEGACY_RLS_SCHEMA, REBASE_SCHEMA } from "@rebasepro/types";
6
6
  import { sqlRows } from "@rebasepro/common";
7
7
  import { suggestNearMiss } from "@rebasepro/utils";
@@ -6194,6 +6194,7 @@ var { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExpo
6194
6194
  //#region src/schema/rls-bootstrap-sql.ts
6195
6195
  var rls_bootstrap_sql_exports = /* @__PURE__ */ __exportAll({
6196
6196
  DROP_LEGACY_AUTH_SCHEMA_SQL: () => DROP_LEGACY_AUTH_SCHEMA_SQL,
6197
+ LEGACY_AUTH_SCHEMA_CONTENTS_SQL: () => LEGACY_AUTH_SCHEMA_CONTENTS_SQL,
6197
6198
  LEGACY_RLS_DEPENDENTS_SQL: () => LEGACY_RLS_DEPENDENTS_SQL,
6198
6199
  LEGACY_RLS_FUNCTION_DEPENDENTS_SQL: () => LEGACY_RLS_FUNCTION_DEPENDENTS_SQL,
6199
6200
  RLS_BOOTSTRAP_SQL: () => RLS_BOOTSTRAP_SQL,
@@ -6358,6 +6359,60 @@ async function rlsRuntimeIsCurrent(run) {
6358
6359
  /** The same statements as one script, for migration files and raw clients. */
6359
6360
  var RLS_BOOTSTRAP_SQL = "-- Rebase schema + RLS helper functions (required by the policies below)\n" + RLS_BOOTSTRAP_STATEMENTS.map((s) => `${s};`).join("\n\n") + "\n";
6360
6361
  /**
6362
+ * The three functions every pre-1.0 release put in `auth`. (The auth tables
6363
+ * lived in `rebase`, or wherever the users collection was declared.)
6364
+ *
6365
+ * `uid()` is matched on either spelling of the principal because Rebase wrote
6366
+ * both. Until v0.10.0 its body was
6367
+ * `SELECT NULLIF(current_setting('app.user_id', true), '')`; v0.10.0 renamed
6368
+ * the GUC to `app.uid` and kept `app.user_id` as a fallback; v0.14.0 moved the
6369
+ * helpers to `rebase`. A database last booted before v0.10.0 therefore holds an
6370
+ * `auth.uid()` that reads `app.user_id` alone — as does anything that copied
6371
+ * that body, the Rebase control plane included — and matching `app.uid` only
6372
+ * left every one of them in place, with the schema around it.
6373
+ *
6374
+ * This is the one place either spelling is listed: the drop and the report of
6375
+ * what it left are both generated from it, so they cannot disagree about which
6376
+ * functions are Rebase's.
6377
+ */
6378
+ var LEGACY_AUTH_HELPERS = [
6379
+ {
6380
+ name: "uid",
6381
+ returns: "text",
6382
+ reads: ["app.uid", "app.user_id"]
6383
+ },
6384
+ {
6385
+ name: "jwt",
6386
+ returns: "jsonb",
6387
+ reads: ["app.jwt"]
6388
+ },
6389
+ {
6390
+ name: "roles",
6391
+ returns: "text",
6392
+ reads: ["app.user_roles"]
6393
+ }
6394
+ ];
6395
+ /**
6396
+ * `pg_proc p` has a Rebase helper's name, arity and result type: what
6397
+ * `CREATE OR REPLACE` would have left, whatever the body.
6398
+ *
6399
+ * Two things that share that shape are excluded outright: a body reading
6400
+ * `request.jwt` (Supabase's helpers and anything modelled on them) and a
6401
+ * function an extension installed (`pg_session_jwt` puts an `auth.jwt()
6402
+ * RETURNS jsonb` in the same schema).
6403
+ */
6404
+ var isLegacyHelperShaped = (helper) => `(
6405
+ p.proname = '${helper.name}' AND p.pronargs = 0
6406
+ AND pg_get_function_result(p.oid) = '${helper.returns}'
6407
+ AND strpos(p.prosrc, 'request.jwt') = 0
6408
+ AND NOT EXISTS (
6409
+ SELECT 1 FROM pg_depend e
6410
+ WHERE e.classid = 'pg_proc'::regclass AND e.objid = p.oid AND e.deptype = 'e'
6411
+ ))`;
6412
+ /** `pg_proc p` is a helper Rebase wrote: its shape, and a body reading one of its GUCs. */
6413
+ var isLegacyHelper = (helper) => `${isLegacyHelperShaped(helper)}
6414
+ AND (${helper.reads.map((guc) => `strpos(p.prosrc, '${guc}') > 0`).join(" OR ")})`;
6415
+ /**
6361
6416
  * Removes the pre-1.0 `auth` schema, but only when Rebase is what put it there.
6362
6417
  *
6363
6418
  * ## Why this is safe against a Supabase database
@@ -6365,11 +6420,12 @@ var RLS_BOOTSTRAP_SQL = "-- Rebase schema + RLS helper functions (required by th
6365
6420
  * Two independent guards, and both have to pass:
6366
6421
  *
6367
6422
  * 1. **Each function is identified before it is dropped.** Ours returns `text`
6368
- * and reads the `app.uid` GUC; Supabase's returns `uuid` and reads
6369
- * `request.jwt.claims`. Nothing is dropped on a signature we did not write,
6370
- * so a Supabase database — where our `CREATE OR REPLACE` could never have
6371
- * succeeded in the first place, Postgres refusing to change a return type —
6372
- * matches nothing and this is a no-op.
6423
+ * and reads the `app.uid` or `app.user_id` GUC; Supabase's returns `uuid`
6424
+ * and reads `request.jwt.claims`. Nothing is dropped on a signature we did
6425
+ * not write, so a Supabase database — where our `CREATE OR REPLACE` could
6426
+ * never have succeeded in the first place, Postgres refusing to change a
6427
+ * return type — matches nothing and this is a no-op. See
6428
+ * {@link LEGACY_AUTH_HELPERS} for exactly what is matched.
6373
6429
  * 2. **`DROP SCHEMA … RESTRICT`**, never CASCADE. If anything else at all still
6374
6430
  * lives in `auth` (Supabase's `users` table, its other helpers), the drop
6375
6431
  * fails and the schema stays. CASCADE here would be unrecoverable.
@@ -6390,41 +6446,21 @@ DECLARE
6390
6446
  BEGIN
6391
6447
  -- Each function is matched on its own result type and body, so a schema
6392
6448
  -- that merely shares the name keeps everything it has.
6393
- IF EXISTS (
6449
+ ${LEGACY_AUTH_HELPERS.map((helper) => ` IF EXISTS (
6394
6450
  SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6395
- WHERE n.nspname = 'auth' AND p.proname = 'uid'
6396
- AND pg_get_function_result(p.oid) = 'text'
6397
- AND p.prosrc LIKE '%app.uid%'
6451
+ WHERE n.nspname = '${LEGACY_RLS_SCHEMA}' AND ${isLegacyHelper(helper)}
6398
6452
  ) THEN
6399
- DROP FUNCTION auth.uid();
6453
+ DROP FUNCTION ${LEGACY_RLS_SCHEMA}.${helper.name}();
6400
6454
  dropped_any := true;
6401
- END IF;
6402
-
6403
- IF EXISTS (
6404
- SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6405
- WHERE n.nspname = 'auth' AND p.proname = 'jwt'
6406
- AND pg_get_function_result(p.oid) = 'jsonb'
6407
- AND p.prosrc LIKE '%app.jwt%'
6408
- ) THEN
6409
- DROP FUNCTION auth.jwt();
6410
- dropped_any := true;
6411
- END IF;
6412
-
6413
- IF EXISTS (
6414
- SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6415
- WHERE n.nspname = 'auth' AND p.proname = 'roles'
6416
- AND pg_get_function_result(p.oid) = 'text'
6417
- AND p.prosrc LIKE '%app.user_roles%'
6418
- ) THEN
6419
- DROP FUNCTION auth.roles();
6420
- dropped_any := true;
6421
- END IF;
6455
+ END IF;`).join("\n\n")}
6422
6456
 
6423
6457
  -- RESTRICT: only an empty schema goes. Anything else in there — including a
6424
- -- Supabase installation left untouched above — keeps it.
6458
+ -- Supabase installation left untouched above — keeps it. Swallowed so the
6459
+ -- helpers dropped above stay dropped; dropLegacyAuthSchema looks afterwards
6460
+ -- and says what is left.
6425
6461
  IF dropped_any THEN
6426
6462
  BEGIN
6427
- EXECUTE 'DROP SCHEMA auth RESTRICT';
6463
+ EXECUTE 'DROP SCHEMA ${LEGACY_RLS_SCHEMA} RESTRICT';
6428
6464
  EXCEPTION WHEN OTHERS THEN
6429
6465
  NULL;
6430
6466
  END;
@@ -6433,6 +6469,40 @@ END
6433
6469
  $rebase_drop_legacy$;
6434
6470
  `;
6435
6471
  /**
6472
+ * What the `auth` schema holds, one row per object keeping it alive.
6473
+ *
6474
+ * No rows: the schema does not exist. A single row with a `null` object: it
6475
+ * exists and is empty. Read from the namespace entries in `pg_depend`, which
6476
+ * are what `DROP SCHEMA … RESTRICT` itself consults — minus whatever goes with
6477
+ * its owner (a serial's sequence, an identity column's), which Postgres does not
6478
+ * name either.
6479
+ */
6480
+ var LEGACY_AUTH_SCHEMA_CONTENTS_SQL = `
6481
+ SELECT pg_describe_object(d.classid, d.objid, d.objsubid) AS object,
6482
+ CASE
6483
+ WHEN d.classid <> 'pg_proc'::regclass THEN NULL
6484
+ WHEN EXISTS (
6485
+ SELECT 1 FROM pg_proc p
6486
+ WHERE p.oid = d.objid
6487
+ AND (${LEGACY_AUTH_HELPERS.map((helper) => `(${isLegacyHelper(helper)})`).join(" OR ")})
6488
+ ) THEN 'ours'
6489
+ WHEN EXISTS (
6490
+ SELECT 1 FROM pg_proc p
6491
+ WHERE p.oid = d.objid
6492
+ AND (${LEGACY_AUTH_HELPERS.map(isLegacyHelperShaped).join(" OR ")})
6493
+ ) THEN 'lookalike'
6494
+ END AS helper
6495
+ FROM pg_namespace n
6496
+ LEFT JOIN pg_depend d
6497
+ ON d.refclassid = 'pg_namespace'::regclass AND d.refobjid = n.oid AND d.deptype = 'n'
6498
+ AND NOT EXISTS (
6499
+ SELECT 1 FROM pg_depend o
6500
+ WHERE o.classid = d.classid AND o.objid = d.objid AND o.deptype IN ('a', 'i')
6501
+ )
6502
+ WHERE n.nspname = '${LEGACY_RLS_SCHEMA}'
6503
+ ORDER BY helper NULLS LAST, object
6504
+ `;
6505
+ /**
6436
6506
  * Policies whose body still calls `auth.uid()` / `auth.roles()` / `auth.jwt()`.
6437
6507
  *
6438
6508
  * Postgres will not drop a function a policy depends on, so this is exactly the
@@ -6463,11 +6533,12 @@ var LEGACY_RLS_DEPENDENTS_SQL = `
6463
6533
  * exists, which fails at *query* time rather than at boot.
6464
6534
  *
6465
6535
  * A downstream project building on these helpers is not hypothetical: the Rebase
6466
- * control plane defines `auth.is_org_member(uuid)` and `auth.is_org_admin(uuid)`
6536
+ * control plane defined `auth.is_org_member(uuid)` and `auth.is_org_admin(uuid)`
6467
6537
  * in this very schema, each calling `auth.uid()` in a string body, and eleven of
6468
- * its row-level-security policies go through them. Every one of those would have
6469
- * started failing the first time a recompile left no policy referencing
6470
- * `auth.uid()` directly — the drop's own precondition.
6538
+ * its row-level-security policies went through them. Every one of those would
6539
+ * have started failing the first time a recompile left no policy referencing
6540
+ * `auth.uid()` directly — the drop's own precondition. (Its migration 0065 has
6541
+ * since moved both to `public`, calling `rebase.uid()`.)
6471
6542
  *
6472
6543
  * Matching on the body text is the only option available, and it is deliberately
6473
6544
  * broad: a false positive costs a schema that stays one release longer and says
@@ -6491,8 +6562,30 @@ var LEGACY_RLS_FUNCTION_DEPENDENTS_SQL = `
6491
6562
  * table not recompiled *yet* — and wrong for the one that never resolves: a
6492
6563
  * hand-written policy nothing will ever rewrite. Then the schema stays forever
6493
6564
  * and nothing ever says why.
6565
+ *
6566
+ * The drop itself had the same blind spot. A helper it did not recognise as
6567
+ * Rebase's stayed, and so did anything else in the schema, behind a
6568
+ * `DROP SCHEMA … RESTRICT` whose failure is swallowed so the helpers it did
6569
+ * drop stay dropped. The control plane's `auth.uid()` was one such: it read
6570
+ * `app.user_id` alone, the drop looked for `app.uid`, and the schema stayed
6571
+ * with no word said. So the schema is read twice. Before, so that one with no
6572
+ * Rebase helper in it is left alone: one already gone, as on every boot after
6573
+ * the drop, or one that was never Rebase's, like Supabase's — whose own
6574
+ * policies the checks below would otherwise report as blockers. After, to name
6575
+ * whatever is still there.
6494
6576
  */
6495
6577
  async function dropLegacyAuthSchema(run, report) {
6578
+ let before;
6579
+ try {
6580
+ before = sqlRows(await run(LEGACY_AUTH_SCHEMA_CONTENTS_SQL));
6581
+ } catch {
6582
+ return;
6583
+ }
6584
+ if (!before.some((o) => o.helper !== null)) return;
6585
+ if (!before.some((o) => o.helper === "ours")) {
6586
+ report.warn(describeLegacyAuthLeftovers(before, void 0));
6587
+ return;
6588
+ }
6496
6589
  let blockers;
6497
6590
  try {
6498
6591
  blockers = sqlRows(await run(LEGACY_RLS_DEPENDENTS_SQL));
@@ -6513,11 +6606,42 @@ async function dropLegacyAuthSchema(run, report) {
6513
6606
  report.warn(`The pre-1.0 \`${LEGACY_RLS_SCHEMA}\` schema cannot be removed yet: ${borrowers.length} ${borrowers.length === 1 ? "function calls" : "functions call"} \`${LEGACY_RLS_SCHEMA}.uid()\` and friends from its own body. Postgres records no dependency for that — a SQL body written as a string literal is never parsed — so dropping the helpers would leave these pointing at nothing, and they would fail when a query reached them rather than now. Repoint them at \`${REBASE_SCHEMA}.uid()\`, after which the schema goes on its own:\n` + borrowers.map((b) => ` • ${b.schema}.${b.function}()`).join("\n"));
6514
6607
  return;
6515
6608
  }
6609
+ let failure;
6516
6610
  try {
6517
6611
  await run(DROP_LEGACY_AUTH_SCHEMA_SQL);
6518
6612
  } catch (err) {
6519
- report.info(`Left the \`${LEGACY_RLS_SCHEMA}\` schema in place: ` + (err instanceof Error ? err.message : String(err)));
6613
+ const detail = err instanceof Error && "detail" in err && typeof err.detail === "string" ? err.detail : "";
6614
+ failure = (err instanceof Error ? err.message : String(err)) + (detail ? ` (${detail.replace(/\n/g, "; ")})` : "");
6520
6615
  }
6616
+ let left;
6617
+ try {
6618
+ left = sqlRows(await run(LEGACY_AUTH_SCHEMA_CONTENTS_SQL));
6619
+ } catch {
6620
+ if (failure) report.info(`Left the \`${LEGACY_RLS_SCHEMA}\` schema in place: ${failure}`);
6621
+ return;
6622
+ }
6623
+ if (left.length === 0) return;
6624
+ report.warn(describeLegacyAuthLeftovers(left, failure));
6625
+ }
6626
+ /** At most this many objects are named; a schema this full is plainly in use. */
6627
+ var MAX_LEFTOVERS_NAMED = 20;
6628
+ /**
6629
+ * The warning for an `auth` schema the drop left standing.
6630
+ *
6631
+ * Said once for objects that are not Rebase's: on the next boot the schema holds
6632
+ * no helper, so {@link dropLegacyAuthSchema} leaves it alone — it is somebody
6633
+ * else's schema by then. A helper that is still there, Rebase's or a lookalike,
6634
+ * keeps it said on every boot until it goes.
6635
+ */
6636
+ function describeLegacyAuthLeftovers(left, failure) {
6637
+ const schema = LEGACY_RLS_SCHEMA;
6638
+ const objects = left.filter((o) => o.object !== null);
6639
+ if (objects.length === 0) return `The pre-1.0 \`${schema}\` schema is empty, but this connection could not drop it — most likely because it does not own the schema. Run \`DROP SCHEMA ${schema};\` as its owner.`;
6640
+ const why = failure ? `dropping Rebase's old helpers from it failed: ${failure}.` : "`DROP SCHEMA … RESTRICT` refuses a schema that is not empty, and Rebase drops only the helpers it can tell are its own.";
6641
+ const lines = objects.slice(0, MAX_LEFTOVERS_NAMED).map((o) => o.helper === "ours" ? ` • ${o.object} — Rebase's old helper, which could not be dropped` : o.helper === "lookalike" ? ` • ${o.object} — named and typed like Rebase's old helper, but no release wrote this body, so it was left alone; drop it by hand if nothing of yours calls it` : ` • ${o.object}`);
6642
+ if (objects.length > MAX_LEFTOVERS_NAMED) lines.push(` • …and ${objects.length - MAX_LEFTOVERS_NAMED} more`);
6643
+ return `The pre-1.0 \`${schema}\` schema is still here: ${why} Still in it:\n` + lines.join("\n") + `
6644
+ Anything of yours can stay where it is — Rebase no longer uses this schema — or move out with \`ALTER … SET SCHEMA\`. Once the schema is empty, \`DROP SCHEMA ${schema};\` removes it.`;
6521
6645
  }
6522
6646
  //#endregion
6523
6647
  //#region src/cli-flags.ts
@@ -6836,6 +6960,10 @@ var BRANCH_ACTION_FLAGS = {
6836
6960
  },
6837
6961
  list: {},
6838
6962
  info: {},
6963
+ diff: {
6964
+ "--json": Boolean,
6965
+ "--sample-limit": Number
6966
+ },
6839
6967
  delete: {
6840
6968
  "--force": Boolean,
6841
6969
  "--yes": Boolean,
@@ -6937,6 +7065,7 @@ function unexpectedBranchArgs(words) {
6937
7065
  var TAKES_A_VALUE = /* @__PURE__ */ new Set([
6938
7066
  "--from",
6939
7067
  "--older-than",
7068
+ "--sample-limit",
6940
7069
  "--database-url"
6941
7070
  ]);
6942
7071
  //#endregion
@@ -6970,6 +7099,102 @@ function isDriverDbSubcommand(word) {
6970
7099
  return DRIVER_DB_SUBCOMMANDS.some((subcommand) => subcommand === word);
6971
7100
  }
6972
7101
  //#endregion
6973
- export { rlsRuntimeIsCurrent as _, resolveBranchSwitches as a, assertKnownFlags as c, parseCommandFlags as d, parseDriverLine as f, dropLegacyAuthSchema as g, RLS_BOOTSTRAP_STATEMENTS as h, assertKnownBranchFlags as i, closestWord as l, RLS_BOOTSTRAP_SQL as m, isDriverDbSubcommand as n, unexpectedBranchArgs as o, resolveDriverSwitches as p, backupActionOf as r, RELAYED_FLAGS as s, DRIVER_DB_SUBCOMMANDS as t, collectionsPathIn as u, rls_bootstrap_sql_exports as v, execa as y };
7102
+ //#region src/schema/migrate-baseline.ts
7103
+ /**
7104
+ * What `rebase db migrate --baseline <version>` does, given the history the
7105
+ * database already has.
7106
+ *
7107
+ * The flag promises to record `<version>` as applied and migrate from the next
7108
+ * one. Atlas's own `migrate apply --baseline` keeps that promise only on a
7109
+ * database with no revision history: once one row exists it ignores the flag
7110
+ * without a word, applies the migration anyway, and the CLI had already printed
7111
+ * "Recording … as already applied". That is the normal second time: a project
7112
+ * baselines once, then `rebase dev` adds a column at boot, `db generate` writes
7113
+ * the migration for it, and `db migrate` fails on `column … already exists
7114
+ * (42701)` however the baseline is spelled.
7115
+ *
7116
+ * So the history is read first. With none, Atlas's baseline does the work.
7117
+ * Behind `<version>`, `atlas migrate set` marks every migration up to it as
7118
+ * applied, which is what a baseline means. At or past it, there is nothing to
7119
+ * record, and the command says so instead of claiming it recorded something.
7120
+ */
7121
+ /**
7122
+ * Atlas's version order for the versions Rebase writes: numeric timestamps,
7123
+ * compared as numbers so a shorter one is not read as later; anything else as
7124
+ * text.
7125
+ */
7126
+ function compareMigrationVersions(a, b) {
7127
+ if (/^\d+$/.test(a) && /^\d+$/.test(b)) {
7128
+ const x = BigInt(a);
7129
+ const y = BigInt(b);
7130
+ return x === y ? 0 : x < y ? -1 : 1;
7131
+ }
7132
+ return a.localeCompare(b);
7133
+ }
7134
+ /**
7135
+ * The version Atlas records for a migration file: its numeric prefix
7136
+ * (`20260906101530_init.sql` → `20260906101530`), or the name without `.sql`.
7137
+ */
7138
+ function migrationVersionOf(file) {
7139
+ return /^(\d+)/.exec(file)?.[1] ?? file.replace(/\.sql$/, "");
7140
+ }
7141
+ /** How many versions a refused baseline names, newest last. */
7142
+ var VERSIONS_NAMED = 5;
7143
+ /**
7144
+ * Why `--baseline <version>` cannot run, or `null` when it names a migration
7145
+ * file in `drizzle/migrations`.
7146
+ *
7147
+ * Asked before anything else, the database included. A version no file has
7148
+ * was refused only by Atlas, after the command had said "Marking every
7149
+ * migration up to abc as applied…"; and one older than every file read
7150
+ * "Nothing to record" and migrated on, though it named nothing to baseline.
7151
+ *
7152
+ * @param files the migration files, sorted oldest first.
7153
+ * @returns the refusal, its first line the error and the rest the detail.
7154
+ */
7155
+ function baselineVersionProblem(version, files) {
7156
+ const versions = files.map(migrationVersionOf);
7157
+ if (versions.length === 0) return `--baseline ${version}: There are no migrations in drizzle/migrations to baseline. Nothing was run.\nRun \`rebase db generate\` to write the first one.`;
7158
+ if (versions.includes(version)) return null;
7159
+ const named = versions.slice(-5).join(", ");
7160
+ return `--baseline ${version} names no migration in drizzle/migrations. Nothing was run.\n${versions.length > VERSIONS_NAMED ? `The newest ${VERSIONS_NAMED} of the ${versions.length} versions there` : "The versions there"}: ${named}. A baseline is one of them: the newest migration the database already holds.`;
7161
+ }
7162
+ /** How to keep `--baseline <version>`'s promise, given the newest recorded version. */
7163
+ function planBaseline(version, latestRecorded) {
7164
+ if (latestRecorded === null) return { kind: "atlas-baseline" };
7165
+ if (compareMigrationVersions(version, latestRecorded) > 0) return {
7166
+ kind: "set",
7167
+ latest: latestRecorded
7168
+ };
7169
+ return {
7170
+ kind: "already-recorded",
7171
+ latest: latestRecorded
7172
+ };
7173
+ }
7174
+ /** What the command says before it migrates, for each plan. */
7175
+ function describeBaselinePlan(version, plan) {
7176
+ switch (plan.kind) {
7177
+ case "atlas-baseline": return `Recording ${version} as already applied, then migrating from the next one.`;
7178
+ case "set": return `This database already records migrations up to ${plan.latest}, and Atlas applies --baseline only to a database with none.\n Marking every migration up to ${version} as applied with \`atlas migrate set\`, then migrating from the next one.`;
7179
+ case "already-recorded": return `Nothing to record: this database already records migrations up to ${plan.latest}, which includes ${version}.\n Migrating from the next one.`;
7180
+ }
7181
+ }
7182
+ /**
7183
+ * The newest version Atlas has recorded on this database, or `null` when it
7184
+ * has recorded none (no revisions table yet included).
7185
+ *
7186
+ * The table is `rebase.atlas_schema_revisions`: the CLI passes
7187
+ * `--revisions-schema rebase` to every `migrate apply`.
7188
+ */
7189
+ async function latestRecordedMigration(databaseUrl) {
7190
+ return withAppClient(databaseUrl, async (client) => {
7191
+ if (!(await client.query("SELECT to_regclass('rebase.atlas_schema_revisions') IS NOT NULL AS present")).rows[0]?.present) return null;
7192
+ const versions = (await client.query("SELECT version FROM rebase.atlas_schema_revisions WHERE version NOT LIKE '.%'")).rows.map((row) => row.version);
7193
+ if (versions.length === 0) return null;
7194
+ return versions.reduce((latest, version) => compareMigrationVersions(version, latest) > 0 ? version : latest);
7195
+ });
7196
+ }
7197
+ //#endregion
7198
+ export { rlsRuntimeIsCurrent as C, dropLegacyAuthSchema as S, execa as T, parseCommandFlags as _, migrationVersionOf as a, RLS_BOOTSTRAP_SQL as b, isDriverDbSubcommand as c, resolveBranchSwitches as d, unexpectedBranchArgs as f, collectionsPathIn as g, closestWord as h, latestRecordedMigration as i, backupActionOf as l, assertKnownFlags as m, compareMigrationVersions as n, planBaseline as o, RELAYED_FLAGS as p, describeBaselinePlan as r, DRIVER_DB_SUBCOMMANDS as s, baselineVersionProblem as t, assertKnownBranchFlags as u, parseDriverLine as v, rls_bootstrap_sql_exports as w, RLS_BOOTSTRAP_STATEMENTS as x, resolveDriverSwitches as y };
6974
7199
 
6975
- //# sourceMappingURL=db-subcommands-BPoHCxJR.js.map
7200
+ //# sourceMappingURL=migrate-baseline-B-2Ef4Mv.js.map