@rebasepro/server-postgres 0.23.0 → 0.24.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 (108) hide show
  1. package/dist/{BranchService-DGPL6G_C.js → BranchService-BRt78gfa.js} +35 -18
  2. package/dist/BranchService-BRt78gfa.js.map +1 -0
  3. package/dist/PostgresBackendDriver.d.ts +84 -12
  4. package/dist/auth/services.d.ts +72 -14
  5. package/dist/{auth-users-columns-D2LBFrMH.js → auth-users-columns-C72EMoDJ.js} +17 -1
  6. package/dist/{auth-users-columns-D2LBFrMH.js.map → auth-users-columns-C72EMoDJ.js.map} +1 -1
  7. package/dist/{backup-cli-24v4OlSp.js → backup-cli-DW5p9_zv.js} +2 -2
  8. package/dist/{backup-cli-24v4OlSp.js.map → backup-cli-DW5p9_zv.js.map} +1 -1
  9. package/dist/{backup-service-HQ9GC4tN.js → backup-service-EwcDVG-8.js} +7 -9
  10. package/dist/{backup-service-HQ9GC4tN.js.map → backup-service-EwcDVG-8.js.map} +1 -1
  11. package/dist/{cli-errors-B8qHg02P.js → cli-errors-DsA-K9uP.js} +96 -1
  12. package/dist/{cli-errors-B8qHg02P.js.map → cli-errors-DsA-K9uP.js.map} +1 -1
  13. package/dist/cli-errors.d.ts +42 -0
  14. package/dist/cli-helpers.d.ts +12 -12
  15. package/dist/cli.js +91 -37
  16. package/dist/cli.js.map +1 -1
  17. package/dist/{column-plan-helpers-DF-8dTVa.js → column-plan-helpers-1-LQD0yI.js} +34 -24
  18. package/dist/column-plan-helpers-1-LQD0yI.js.map +1 -0
  19. package/dist/data-transformer.d.ts +0 -8
  20. package/dist/{doctor-Cb2thZ8s.js → doctor-C-sYWbmt.js} +224 -43
  21. package/dist/doctor-C-sYWbmt.js.map +1 -0
  22. package/dist/{ensure-collection-policies-RHUcEp4v.js → ensure-collection-policies-B1ureSIV.js} +73 -18
  23. package/dist/ensure-collection-policies-B1ureSIV.js.map +1 -0
  24. package/dist/{ensure-collection-tables-BEEjn5cn.js → ensure-collection-tables-kkkHk8oo.js} +76 -20
  25. package/dist/ensure-collection-tables-kkkHk8oo.js.map +1 -0
  26. package/dist/{ensure-tables-Dhn9KM3B.js → ensure-tables-BmI_tRxc.js} +10 -3
  27. package/dist/ensure-tables-BmI_tRxc.js.map +1 -0
  28. package/dist/{generate-drizzle-schema-yzY_BLhr.js → generate-drizzle-schema-93M0lUxK.js} +2 -2
  29. package/dist/{generate-drizzle-schema-yzY_BLhr.js.map → generate-drizzle-schema-93M0lUxK.js.map} +1 -1
  30. package/dist/{generate-drizzle-schema-logic-BfzK7UQd.js → generate-drizzle-schema-logic-sSFDp6LR.js} +26 -8
  31. package/dist/generate-drizzle-schema-logic-sSFDp6LR.js.map +1 -0
  32. package/dist/generate-postgres-ddl-logic-BJsLaVNX.js +152 -0
  33. package/dist/generate-postgres-ddl-logic-BJsLaVNX.js.map +1 -0
  34. package/dist/generated-sql.d.ts +28 -0
  35. package/dist/index.es.js +3415 -917
  36. package/dist/index.es.js.map +1 -1
  37. package/dist/{introspect-db-logic-WMuAfxvw.js → introspect-db-logic-kCETE8TY.js} +523 -349
  38. package/dist/introspect-db-logic-kCETE8TY.js.map +1 -0
  39. package/dist/introspect-db-queries-C_Q5VgQw.js +317 -0
  40. package/dist/introspect-db-queries-C_Q5VgQw.js.map +1 -0
  41. package/dist/{plan-schema-C0fxM8dY.js → plan-schema-DU9exq6C.js} +139 -504
  42. package/dist/plan-schema-DU9exq6C.js.map +1 -0
  43. package/dist/{policy-drift-DljYdrpW.js → policy-drift-B-J2hhm0.js} +3 -3
  44. package/dist/policy-drift-B-J2hhm0.js.map +1 -0
  45. package/dist/{generate-postgres-ddl-logic-Bt2d2mRH.js → render-ddl-Ds2t_d9V.js} +11 -149
  46. package/dist/render-ddl-Ds2t_d9V.js.map +1 -0
  47. package/dist/{rls-bootstrap-sql-B8EclDyM.js → rls-bootstrap-sql-_KNnjanK.js} +263 -39
  48. package/dist/rls-bootstrap-sql-_KNnjanK.js.map +1 -0
  49. package/dist/{rls-enforcement-C6Xk0lA6.js → rls-enforcement-CfXOJJaW.js} +10 -2
  50. package/dist/rls-enforcement-CfXOJJaW.js.map +1 -0
  51. package/dist/schema/auth-schema.d.ts +170 -0
  52. package/dist/schema/classify-change.d.ts +29 -1
  53. package/dist/schema/column-plan-helpers.d.ts +33 -21
  54. package/dist/schema/destructive-sql.d.ts +20 -1
  55. package/dist/schema/doctor-cli.js +4 -4
  56. package/dist/schema/doctor.d.ts +34 -1
  57. package/dist/schema/ensure-collection-policies.d.ts +22 -0
  58. package/dist/schema/generate-drizzle-schema.js +1 -1
  59. package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -5
  60. package/dist/schema/generate-postgres-ddl.js +1 -1
  61. package/dist/schema/generate-schema-commit.d.ts +12 -0
  62. package/dist/schema/introspect-db-logic.d.ts +31 -0
  63. package/dist/schema/introspect-db-queries.d.ts +1 -1
  64. package/dist/schema/introspect-db-search.d.ts +22 -0
  65. package/dist/schema/introspect-db-storage.d.ts +83 -0
  66. package/dist/schema/introspect-db.js +15 -3
  67. package/dist/schema/introspect-db.js.map +1 -1
  68. package/dist/schema/plan/diff-plan.d.ts +1 -1
  69. package/dist/schema/plan/plan-schema.d.ts +16 -8
  70. package/dist/schema/plan/render-ddl.d.ts +6 -0
  71. package/dist/schema/plan/types.d.ts +37 -11
  72. package/dist/search-column-BM-GV6vH.js +442 -0
  73. package/dist/search-column-BM-GV6vH.js.map +1 -0
  74. package/dist/security/policy-drift.d.ts +1 -1
  75. package/dist/security/rls-enforcement.d.ts +7 -0
  76. package/dist/services/BranchService.d.ts +22 -1
  77. package/dist/services/FetchService.d.ts +5 -4
  78. package/dist/services/RelationService.d.ts +18 -0
  79. package/dist/services/cdc/CdcListener.d.ts +9 -4
  80. package/dist/services/cdc/identity-columns.d.ts +19 -0
  81. package/dist/services/cdc/trigger-cdc.d.ts +45 -7
  82. package/dist/services/channel-bus/PostgresChannelBus.d.ts +12 -7
  83. package/dist/services/channel-history.d.ts +17 -1
  84. package/dist/services/collection-helpers.d.ts +11 -1
  85. package/dist/services/pg-notify-listener.d.ts +88 -6
  86. package/dist/services/realtimeService.d.ts +159 -45
  87. package/dist/services/socket-liveness.d.ts +45 -0
  88. package/dist/services/soft-delete.d.ts +12 -0
  89. package/dist/services/sql-script.d.ts +71 -0
  90. package/dist/services/write-depth.d.ts +16 -0
  91. package/dist/services/write-transaction-scope.d.ts +6 -3
  92. package/dist/utils/drizzle-conditions.d.ts +42 -2
  93. package/dist/utils/sql-redaction.d.ts +21 -0
  94. package/dist/websocket.d.ts +50 -18
  95. package/package.json +7 -7
  96. package/dist/BranchService-DGPL6G_C.js.map +0 -1
  97. package/dist/column-plan-helpers-DF-8dTVa.js.map +0 -1
  98. package/dist/doctor-Cb2thZ8s.js.map +0 -1
  99. package/dist/ensure-collection-policies-RHUcEp4v.js.map +0 -1
  100. package/dist/ensure-collection-tables-BEEjn5cn.js.map +0 -1
  101. package/dist/ensure-tables-Dhn9KM3B.js.map +0 -1
  102. package/dist/generate-drizzle-schema-logic-BfzK7UQd.js.map +0 -1
  103. package/dist/generate-postgres-ddl-logic-Bt2d2mRH.js.map +0 -1
  104. package/dist/introspect-db-logic-WMuAfxvw.js.map +0 -1
  105. package/dist/plan-schema-C0fxM8dY.js.map +0 -1
  106. package/dist/policy-drift-DljYdrpW.js.map +0 -1
  107. package/dist/rls-bootstrap-sql-B8EclDyM.js.map +0 -1
  108. package/dist/rls-enforcement-C6Xk0lA6.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  __createRequire(import.meta.url);
3
3
  import { a as __toESM } from "./__vite-browser-external-BnuHet1e.js";
4
- import { a as formatForeignGeneratedColumnBanner, c as reportCommandFailure, i as diagnoseDbError, r as diagnoseAtlasFailure, t as checkDatabaseConnectivity } from "./cli-errors-B8qHg02P.js";
4
+ import { a as formatForeignGeneratedColumnBanner, c as reportCommandFailure, i as diagnoseDbError, r as diagnoseAtlasFailure, t as checkDatabaseConnectivity } from "./cli-errors-DsA-K9uP.js";
5
5
  import { n as outError, r as outWarn, t as out } from "./cli-output-CNdMql-L.js";
6
- import { A as resolveLocalBin, C as loadCollectionsForCli, D as readSearchDdl, E as queryGeneratedColumnDependencies, F as forLibpq, M as detectDestructiveStatements, N as splitSqlStatements, O as readTriggersDdl, P as execa, S as getVectorExcludes, T as queryColumnTypes, _ as getDevDatabaseUrl, a as ExcludeIntrospectionError, b as getTableExcludes, c as applyVectorDdl, d as describeReinstallCommand, f as detectProjectPackageManager, g as ensureDevDatabaseExists, h as dropGeneratedColumns, j as decidePushSafety, k as readVectorDdl, l as describeBuildScriptRemedy, m as dropDevDatabase, o as applySearchDdl, p as diagnoseMissingBin, r as dropLegacyAuthSchema, s as applyTriggersDdl, t as RLS_BOOTSTRAP_SQL, u as describeDevAddCommand, v as getForeignIndexExcludes, w as promptConfirm, x as getTriggerExcludes, y as getSearchExcludes } from "./rls-bootstrap-sql-B8EclDyM.js";
6
+ import { A as resolveLocalBin, B as forLibpq, C as loadCollectionsForCli, D as readSearchDdl, E as queryGeneratedColumnDependencies, F as decidePushSafety, I as detectDestructiveStatements, L as extractPlanStatements, M as GENERATED_SQL_DIR, N as generatedSqlDir, O as readTriggersDdl, P as prepareGeneratedSqlDir, R as fromAlterTable, S as getVectorExcludes, T as queryColumnTypes, _ as getDevDatabaseUrl, a as ExcludeIntrospectionError, b as getTableExcludes, c as applyVectorDdl, d as describeReinstallCommand, f as detectProjectPackageManager, g as ensureDevDatabaseExists, h as dropGeneratedColumns, j as DESIRED_STATE_URL, k as readVectorDdl, l as describeBuildScriptRemedy, m as dropDevDatabase, o as applySearchDdl, p as diagnoseMissingBin, r as dropLegacyAuthSchema, s as applyTriggersDdl, t as RLS_BOOTSTRAP_SQL, u as describeDevAddCommand, v as getForeignIndexExcludes, w as promptConfirm, x as getTriggerExcludes, y as getSearchExcludes, z as execa } from "./rls-bootstrap-sql-_KNnjanK.js";
7
7
  import { t as chalk } from "./source-Br7L7GOI.js";
8
8
  import { t as require_arg } from "./arg-Dni7MzLB.js";
9
9
  import { n as collectionsPathIn, r as parseDriverLine, t as assertKnownFlags } from "./cli-flags-BglvpjHv.js";
@@ -51,16 +51,6 @@ var ALTER_COLUMN_RE = new RegExp(String.raw`\bALTER\s+(?:COLUMN\s+)?(${IDENT$1})
51
51
  var DROP_COLUMN_RE$1 = new RegExp(String.raw`\bDROP\s+COLUMN\s+(?:IF\s+EXISTS\s+)?(${IDENT$1})`, "gi");
52
52
  var unquote = (ident) => ident.startsWith("\"") ? ident.slice(1, -1) : ident;
53
53
  /**
54
- * Strip Atlas's plan rendering from a statement.
55
- *
56
- * What `schema apply --dry-run` prints is not a SQL file: each statement is
57
- * indented under a `-- modify "posts" table` heading and prefixed with `-> `,
58
- * with an `-- ok (12µs)` line after it. `splitSqlStatements` drops the comment
59
- * lines, and this drops the arrow — without it an anchored `^ALTER TABLE`
60
- * matches nothing at all, which is a silent no-op rather than an error.
61
- */
62
- var stripPlanMarker = (statement) => statement.replace(/^\s*->\s*/, "").trim();
63
- /**
64
54
  * Every column an Atlas plan retypes or drops, with the table it belongs to.
65
55
  *
66
56
  * One statement carries many clauses — Atlas emits `ALTER TABLE "public"."posts"
@@ -69,8 +59,8 @@ var stripPlanMarker = (statement) => statement.replace(/^\s*->\s*/, "").trim();
69
59
  */
70
60
  function parseColumnMutations(planSql) {
71
61
  const mutations = [];
72
- for (const raw of splitSqlStatements(planSql)) {
73
- const statement = stripPlanMarker(raw);
62
+ for (const raw of extractPlanStatements(planSql)) {
63
+ const statement = fromAlterTable(raw);
74
64
  const table = TABLE_RE.exec(statement);
75
65
  if (!table) continue;
76
66
  const [schema, name] = table[2] ? [unquote(table[1]), unquote(table[2])] : [void 0, unquote(table[1])];
@@ -705,8 +695,8 @@ var TAKES_A_VALUE = /* @__PURE__ */ new Set([
705
695
  * `schemaCommand`, `generatePostgresDdlCommand` and the Atlas argv assembly
706
696
  * each re-enter the loader with the same line — and then both generators wrote
707
697
  * an *empty* schema: `drizzle/schema.sql` truncated to `CREATE SCHEMA IF NOT
708
- * EXISTS "rebase";`, `src/schema.generated.ts` to ten lines. Both are committed
709
- * artifacts. The push that followed planned a `DROP TABLE` for every table in
698
+ * EXISTS "rebase";`, `src/schema.generated.ts` to ten lines. Both were committed
699
+ * artifacts then. The push that followed planned a `DROP TABLE` for every table in
710
700
  * the database, and the only thing between a typo and that was the destructive
711
701
  * gate.
712
702
  *
@@ -1021,7 +1011,7 @@ async function dbCommand(subcommand, rawArgs) {
1021
1011
  return;
1022
1012
  }
1023
1013
  if (subcommand === "backup" || subcommand === "restore" || subcommand === "backups") {
1024
- const { backupCommand, restoreCommand, backupsCommand } = await import("./backup-cli-24v4OlSp.js");
1014
+ const { backupCommand, restoreCommand, backupsCommand } = await import("./backup-cli-DW5p9_zv.js");
1025
1015
  if (subcommand === "backup" && backupActionOf(rawArgs) === "list") await backupsCommand(rawArgs);
1026
1016
  else if (subcommand === "backup") await backupCommand(rawArgs);
1027
1017
  else if (subcommand === "restore") await restoreCommand(rawArgs);
@@ -1048,7 +1038,7 @@ async function dbCommand(subcommand, rawArgs) {
1048
1038
  "--dir",
1049
1039
  "file://drizzle/migrations",
1050
1040
  "--to",
1051
- "file://drizzle/schema.sql"
1041
+ DESIRED_STATE_URL
1052
1042
  ], collectionsPath);
1053
1043
  let wroteNewMigration = listMigrationFiles().length > migrationsBefore.length;
1054
1044
  if (wroteNewMigration) wroteNewMigration = await stripCarvedOutFromNewestMigration(collectionsPath);
@@ -1067,7 +1057,7 @@ async function dbCommand(subcommand, rawArgs) {
1067
1057
  }
1068
1058
  const searchContent = readSearchDdl();
1069
1059
  if (searchContent) {
1070
- const { searchColumnDependencies } = await import("./generate-postgres-ddl-logic-Bt2d2mRH.js").then((n) => n.o);
1060
+ const { searchColumnDependencies } = await import("./generate-postgres-ddl-logic-BJsLaVNX.js").then((n) => n.o);
1071
1061
  const migrationConflicts = findGeneratedColumnConflicts(parseColumnMutations(migrationContent), searchColumnDependencies(await loadCollectionsForCli(collectionsPath)));
1072
1062
  const preamble = migrationDropPreamble(migrationConflicts);
1073
1063
  if (preamble) {
@@ -1083,7 +1073,7 @@ async function dbCommand(subcommand, rawArgs) {
1083
1073
  out(chalk.gray(" ✓ Appended `updated_at` triggers to the migration"));
1084
1074
  }
1085
1075
  fs.writeFileSync(newestMigrationFile, migrationContent, "utf-8");
1086
- const policiesFile = path.resolve(process.cwd(), "drizzle", "policies.sql");
1076
+ const policiesFile = path.join(generatedSqlDir(), "policies.sql");
1087
1077
  if (fs.existsSync(policiesFile)) {
1088
1078
  const policiesContent = fs.readFileSync(policiesFile, "utf-8");
1089
1079
  fs.appendFileSync(newestMigrationFile, "\n\n" + RLS_BOOTSTRAP_SQL + "\n" + policiesContent);
@@ -1101,7 +1091,10 @@ async function dbCommand(subcommand, rawArgs) {
1101
1091
  } catch (err) {
1102
1092
  outWarn(chalk.yellow(` ⚠️ Failed to append policies or re-hash migration: ${err instanceof Error ? err.message : String(err)}`));
1103
1093
  }
1104
- if (!wroteNewMigration) out(chalk.gray(" ℹ No migration written — nothing in this change is visible to Atlas.\n Search, vector, trigger and RLS DDL are applied by `rebase db push`, and at\n boot by the schema ensure. For a migration-only deployment, add\n drizzle/search.sql, drizzle/vector.sql, drizzle/triggers.sql and\n drizzle/policies.sql to a migration by hand."));
1094
+ if (!wroteNewMigration) out(chalk.gray(` ℹ No migration written — nothing in this change is visible to Atlas.
1095
+ Search, vector, trigger and RLS DDL are applied by \`rebase db push\`, and at
1096
+ boot by the schema ensure. For a migration-only deployment, add
1097
+ ${GENERATED_SQL_DIR}/search.sql, vector.sql, triggers.sql and\n policies.sql to a migration by hand.`));
1105
1098
  out("");
1106
1099
  out(` You can now run ${chalk.bold.green("rebase db migrate")} to apply the migrations to your database.`);
1107
1100
  out("");
@@ -1123,17 +1116,20 @@ async function dbCommand(subcommand, rawArgs) {
1123
1116
  const plan = await runAtlas("schema", [
1124
1117
  "apply",
1125
1118
  "--to",
1126
- "file://drizzle/schema.sql",
1119
+ DESIRED_STATE_URL,
1127
1120
  "--dry-run"
1128
1121
  ], collectionsPath, { captureStdout: true });
1129
1122
  const destructive = detectDestructiveStatements(plan, databaseUrl ? await queryColumnTypes(databaseUrl) : []);
1123
+ const unreadable = destructive.some((d) => d.kind === "UNREADABLE PLAN");
1124
+ const planStatements = extractPlanStatements(plan);
1125
+ const planListing = unreadable ? plan.trim() : planStatements.map((statement) => `${statement};`).join("\n");
1130
1126
  const { managed: rebuildable, foreign: unowned } = partitionByOwnership(databaseUrl ? findGeneratedColumnConflicts(parseColumnMutations(plan), await queryGeneratedColumnDependencies(databaseUrl)) : [], collectionsPath ? await getSearchExcludes(collectionsPath) : []);
1131
1127
  if (dryRun) {
1132
1128
  out(chalk.gray(" Step 3/3: --dry-run — nothing was applied."));
1133
1129
  out("");
1134
- if (plan.trim()) {
1130
+ if (planStatements.length > 0 || unreadable) {
1135
1131
  out(chalk.bold(" Planned changes:"));
1136
- out(chalk.gray(plan.trim().split("\n").map((l) => ` ${l}`).join("\n")));
1132
+ out(chalk.gray(planListing.split("\n").map((l) => ` ${l}`).join("\n")));
1137
1133
  } else out(chalk.green(" ✓ No changes: the database already matches these collections."));
1138
1134
  out("");
1139
1135
  if (rebuildable.length > 0) {
@@ -1171,7 +1167,7 @@ async function dbCommand(subcommand, rawArgs) {
1171
1167
  for (const d of destructive) outWarn(chalk.red(` ${d.kind}${d.detail ? ` (${d.detail})` : ""}: `) + chalk.gray(d.statement.replace(/\s+/g, " ")));
1172
1168
  outWarn("");
1173
1169
  outWarn(chalk.yellow(" Full planned changes:"));
1174
- outWarn(chalk.gray(plan.trim().split("\n").map((l) => ` ${l}`).join("\n")));
1170
+ outWarn(chalk.gray(planListing.split("\n").map((l) => ` ${l}`).join("\n")));
1175
1171
  outWarn("");
1176
1172
  if (decision === "refuse") {
1177
1173
  outError(chalk.red(" ✗ Aborting: destructive changes require confirmation."));
@@ -1193,9 +1189,9 @@ async function dbCommand(subcommand, rawArgs) {
1193
1189
  await runAtlas("schema", [
1194
1190
  "apply",
1195
1191
  "--to",
1196
- "file://drizzle/schema.sql",
1192
+ DESIRED_STATE_URL,
1197
1193
  "--auto-approve"
1198
- ], collectionsPath);
1194
+ ], collectionsPath, { throwOnFailure: true });
1199
1195
  } catch (err) {
1200
1196
  if (rebuildable.length > 0 && databaseUrl) {
1201
1197
  out(chalk.gray(" The apply failed — rebuilding the generated columns it needed out of the way."));
@@ -1205,6 +1201,7 @@ async function dbCommand(subcommand, rawArgs) {
1205
1201
  }
1206
1202
  out("");
1207
1203
  if (databaseUrl) {
1204
+ await lockManagedTables(databaseUrl, collectionsPath);
1208
1205
  await ensureAuthTables(databaseUrl, collectionsPath);
1209
1206
  await applyVectorDdl(databaseUrl);
1210
1207
  await applySearchDdl(databaseUrl);
@@ -1248,6 +1245,58 @@ async function ensureAuthSchemaAndFunctions(databaseUrl) {
1248
1245
  }
1249
1246
  }
1250
1247
  /**
1248
+ * Switch row-level security on for every table the collections declare, right
1249
+ * after Atlas has applied the schema.
1250
+ *
1251
+ * Atlas cannot carry `ENABLE ROW LEVEL SECURITY` in `schema.sql`: its free tier
1252
+ * neither plans it nor reads it back, so a table it creates is born with RLS
1253
+ * off — and `rebase_user`, the role every authenticated request runs as, holds
1254
+ * DML on it from that moment through the schema's default privileges. RLS used
1255
+ * to arrive with the policies, the last step of the push; a refusal from the
1256
+ * vector, search or trigger step in between left the new table readable and
1257
+ * writable by every caller, with no policy, until a later push or boot fixed
1258
+ * it — and a deployment with `REBASE_MIGRATE_ON_BOOT=none` never did. Locked
1259
+ * first, a failure later leaves a table that denies, not one that is open.
1260
+ *
1261
+ * Fatal when a table cannot be locked, and before the steps that follow: the
1262
+ * role provisioning at the end re-grants on every table in the schema, which
1263
+ * would undo the revoke that is the fallback here.
1264
+ */
1265
+ async function lockManagedTables(databaseUrl, collectionsPath) {
1266
+ let unsecured;
1267
+ let userRole;
1268
+ try {
1269
+ const { lockCollectionTables } = await import("./ensure-collection-policies-B1ureSIV.js");
1270
+ const { loadCollections } = await import("./doctor-C-sYWbmt.js").then((n) => n.t);
1271
+ userRole = (await import("./rls-enforcement-CfXOJJaW.js").then((n) => n.o)).REBASE_USER_ROLE;
1272
+ const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));
1273
+ const { Client } = await import("pg");
1274
+ const client = new Client({ connectionString: databaseUrl });
1275
+ await client.connect();
1276
+ try {
1277
+ ({unsecured} = await lockCollectionTables({ query: async (text) => ({ rows: (await client.query(text)).rows }) }, collections));
1278
+ } finally {
1279
+ await client.end();
1280
+ }
1281
+ } catch (err) {
1282
+ outError(chalk.red(`\n ✗ The schema was applied, but row-level security could not be switched on for its tables: ${err instanceof Error ? err.message : String(err)}`));
1283
+ outError(chalk.gray(" A table this push created may be readable and writable by every authenticated request\n until it is. Re-run `rebase db push` — it locks every collection table before anything else."));
1284
+ process.exit(1);
1285
+ }
1286
+ if (unsecured.length === 0) return;
1287
+ outError(chalk.red("\n ✗ The schema was applied, but row-level security could not be switched on for:"));
1288
+ for (const u of unsecured) {
1289
+ outError(chalk.red(` ${u.table}: ${u.error}`));
1290
+ outError(chalk.gray(u.grantWithdrawn ? ` Its privileges were taken back from ${userRole}, so it is unreachable rather than unprotected.` : ` ${userRole} still holds its privileges: every authenticated request can read and write every row.`));
1291
+ }
1292
+ outError(chalk.gray(" Nothing after the schema apply ran. Fix the cause — the connection role must own these\n tables, or be able to ALTER them — and run `rebase db push` again, or as their owner:"));
1293
+ for (const u of unsecured) {
1294
+ const [schema, ...table] = u.table.split(".");
1295
+ outError(chalk.bold(` ALTER TABLE "${schema}"."${table.join(".")}" ENABLE ROW LEVEL SECURITY;`));
1296
+ }
1297
+ process.exit(1);
1298
+ }
1299
+ /**
1251
1300
  * Create the framework auth tables (e.g. `rebase.users`) that the generated RLS
1252
1301
  * policies reference, before `applyPolicies` runs. Mirrors what the server does
1253
1302
  * at boot (`PostgresBootstrapper.initializeAuth` → `ensureAuthTablesExist`).
@@ -1261,8 +1310,8 @@ async function ensureAuthSchemaAndFunctions(databaseUrl) {
1261
1310
  async function ensureAuthTables(databaseUrl, collectionsPath) {
1262
1311
  try {
1263
1312
  const { drizzle } = await import("drizzle-orm/node-postgres");
1264
- const { ensureAuthTablesExist } = await import("./ensure-tables-Dhn9KM3B.js").then((n) => n.n);
1265
- const { loadCollections } = await import("./doctor-Cb2thZ8s.js").then((n) => n.t);
1313
+ const { ensureAuthTablesExist } = await import("./ensure-tables-BmI_tRxc.js").then((n) => n.n);
1314
+ const { loadCollections } = await import("./doctor-C-sYWbmt.js").then((n) => n.t);
1266
1315
  const { Client } = await import("pg");
1267
1316
  const authCollection = (await loadCollections(path.resolve(process.cwd(), collectionsPath))).find((c) => {
1268
1317
  const a = c.auth;
@@ -1289,7 +1338,7 @@ async function ensureRlsUserRole(databaseUrl) {
1289
1338
  const schemas = ["public", "rebase"];
1290
1339
  let rls;
1291
1340
  try {
1292
- rls = await import("./rls-enforcement-C6Xk0lA6.js").then((n) => n.a);
1341
+ rls = await import("./rls-enforcement-CfXOJJaW.js").then((n) => n.o);
1293
1342
  } catch (err) {
1294
1343
  outError(chalk.red(`\n ✗ Could not load the RLS provisioning module: ${err instanceof Error ? err.message : String(err)}`));
1295
1344
  return;
@@ -1338,7 +1387,7 @@ async function retireLegacyAuthSchema(databaseUrl) {
1338
1387
  }
1339
1388
  async function applyPolicies(databaseUrl) {
1340
1389
  try {
1341
- const policiesPath = path.resolve(process.cwd(), "drizzle", "policies.sql");
1390
+ const policiesPath = path.join(generatedSqlDir(), "policies.sql");
1342
1391
  if (!fs.existsSync(policiesPath)) return;
1343
1392
  out(chalk.gray(" Step 3/3: Applying RLS policies to database..."));
1344
1393
  out("");
@@ -1374,8 +1423,8 @@ async function applyPolicies(databaseUrl) {
1374
1423
  */
1375
1424
  async function reconcilePolicies(databaseUrl, collectionsPath) {
1376
1425
  try {
1377
- const { checkPolicyDrift, dropOrphanedPolicies, formatPolicyDrift, hasDrift } = await import("./policy-drift-DljYdrpW.js").then((n) => n.a);
1378
- const { loadCollections } = await import("./doctor-Cb2thZ8s.js").then((n) => n.t);
1426
+ const { checkPolicyDrift, dropOrphanedPolicies, formatPolicyDrift, hasDrift } = await import("./policy-drift-B-J2hhm0.js").then((n) => n.a);
1427
+ const { loadCollections } = await import("./doctor-C-sYWbmt.js").then((n) => n.t);
1379
1428
  const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));
1380
1429
  const { Client } = await import("pg");
1381
1430
  const client = new Client({ connectionString: databaseUrl });
@@ -1457,7 +1506,7 @@ async function branchCommand(rawArgs) {
1457
1506
  process.exit(1);
1458
1507
  }
1459
1508
  const { DatabasePoolManager } = await import("./databasePoolManager-Bj5FbeAs.js").then((n) => n.n);
1460
- const { BranchService } = await import("./BranchService-DGPL6G_C.js").then((n) => n.n);
1509
+ const { BranchService } = await import("./BranchService-BRt78gfa.js").then((n) => n.n);
1461
1510
  const { drizzle } = await import("drizzle-orm/node-postgres");
1462
1511
  const { Pool } = await import("pg");
1463
1512
  const pool = new Pool({
@@ -1816,6 +1865,7 @@ async function runAtlas(domain, args, collectionsPath, opts = {}) {
1816
1865
  latestMigrationVersion: latestMigrationVersion()
1817
1866
  }) ?? diagnoseDbError({ message: stderrText }, databaseUrl);
1818
1867
  if (hint) outError(hint);
1868
+ if (opts.throwOnFailure) throw Object.assign(/* @__PURE__ */ new Error(`atlas ${domain} ${args.join(" ")} failed`), { alreadyReported: true });
1819
1869
  process.exit(1);
1820
1870
  }
1821
1871
  if (opts.captureStdout) return stdoutText.trim().length > 0 ? stdoutText : stderrText;
@@ -1837,7 +1887,11 @@ async function generatePostgresDdlCommand(rawArgs) {
1837
1887
  process.exit(1);
1838
1888
  }
1839
1889
  const collectionsPath = argsList["--collections"] || path.join("..", "config", "collections");
1840
- const outputPath = argsList["--output"] || path.join("drizzle", "schema.sql");
1890
+ const outputPath = argsList["--output"] || path.join(".rebase/sql", "schema.sql");
1891
+ if (!argsList["--output"]) {
1892
+ const retired = prepareGeneratedSqlDir();
1893
+ if (retired.length > 0) out(chalk.gray(` Generated SQL is written to ${GENERATED_SQL_DIR}/ now, which is not committed. Removed the old copies — commit the deletion:\n ${retired.join(", ")}`));
1894
+ }
1841
1895
  const cmdParts = [
1842
1896
  ddl.bin,
1843
1897
  ddl.script,
@@ -1889,9 +1943,9 @@ async function schemaStaleCommand(rawArgs) {
1889
1943
  const schemaFile = path.resolve(process.cwd(), outputPath);
1890
1944
  const fix = Boolean(argsList["--fix"]);
1891
1945
  const generatedExists = fs.existsSync(schemaFile);
1892
- const { loadCollections } = await import("./doctor-Cb2thZ8s.js").then((n) => n.t);
1946
+ const { loadCollections } = await import("./doctor-C-sYWbmt.js").then((n) => n.t);
1893
1947
  const { findLegacyForeignKeyNames, compareGeneratedDeclarations, staleVerdict } = await import("./generated-schema-staleness-Di9c4ZxN.js").then((n) => n.r);
1894
- const { generateSchema } = await import("./generate-drizzle-schema-logic-BfzK7UQd.js").then((n) => n.n);
1948
+ const { generateSchema } = await import("./generate-drizzle-schema-logic-sSFDp6LR.js").then((n) => n.n);
1895
1949
  const { relationalCollections } = await import("@rebasepro/common");
1896
1950
  let stale = [];
1897
1951
  let differences = [];