@rebasepro/server-postgres 0.23.0 → 0.24.1-canary.g19596ef

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 (208) hide show
  1. package/README.md +16 -0
  2. package/dist/{BranchService-DGPL6G_C.js → BranchService-UgKa416x.js} +47 -19
  3. package/dist/BranchService-UgKa416x.js.map +1 -0
  4. package/dist/PostgresBackendDriver.d.ts +187 -13
  5. package/dist/PostgresBootstrapper.d.ts +101 -2
  6. package/dist/auth/ensure-tables.d.ts +12 -0
  7. package/dist/auth/services.d.ts +78 -14
  8. package/dist/{auth-users-columns-D2LBFrMH.js → auth-users-columns-C72EMoDJ.js} +17 -1
  9. package/dist/{auth-users-columns-D2LBFrMH.js.map → auth-users-columns-C72EMoDJ.js.map} +1 -1
  10. package/dist/backup/backup-cli.d.ts +75 -2
  11. package/dist/backup/backup-service.d.ts +2 -2
  12. package/dist/backup/pg-binary.d.ts +5 -0
  13. package/dist/{backup-cli-24v4OlSp.js → backup-cli-yiKd1GsC.js} +168 -75
  14. package/dist/backup-cli-yiKd1GsC.js.map +1 -0
  15. package/dist/{backup-service-HQ9GC4tN.js → backup-service-AZWc2wvI.js} +104 -35
  16. package/dist/backup-service-AZWc2wvI.js.map +1 -0
  17. package/dist/boot-ddl-B9ZmBJ75.js +105 -0
  18. package/dist/boot-ddl-B9ZmBJ75.js.map +1 -0
  19. package/dist/cli-console-DGee3Zl7.js +225 -0
  20. package/dist/cli-console-DGee3Zl7.js.map +1 -0
  21. package/dist/cli-console.d.ts +39 -0
  22. package/dist/cli-errors-oVUuD8k0.js +2180 -0
  23. package/dist/cli-errors-oVUuD8k0.js.map +1 -0
  24. package/dist/cli-errors.d.ts +133 -9
  25. package/dist/{cli-flags-BglvpjHv.js → cli-flags-DnPHXjRH.js} +56 -6
  26. package/dist/cli-flags-DnPHXjRH.js.map +1 -0
  27. package/dist/cli-flags.d.ts +15 -0
  28. package/dist/cli-helpers.d.ts +88 -34
  29. package/dist/cli-output.d.ts +16 -28
  30. package/dist/{arg-Dni7MzLB.js → cli-prompt-egtNKkZl.js} +49 -3
  31. package/dist/cli-prompt-egtNKkZl.js.map +1 -0
  32. package/dist/cli-prompt.d.ts +19 -0
  33. package/dist/cli-push.d.ts +87 -0
  34. package/dist/cli-scratch-database.d.ts +33 -8
  35. package/dist/cli.js +826 -230
  36. package/dist/cli.js.map +1 -1
  37. package/dist/{column-plan-helpers-DF-8dTVa.js → column-plan-helpers-D_V4oaZh.js} +43 -27
  38. package/dist/column-plan-helpers-D_V4oaZh.js.map +1 -0
  39. package/dist/{databasePoolManager-Bj5FbeAs.js → connection-C938nR3E.js} +25 -113
  40. package/dist/connection-C938nR3E.js.map +1 -0
  41. package/dist/connection.d.ts +13 -2
  42. package/dist/data-transformer.d.ts +0 -8
  43. package/dist/databasePoolManager-DZgnBOgj.js +119 -0
  44. package/dist/databasePoolManager-DZgnBOgj.js.map +1 -0
  45. package/dist/deferred-index-build-BqmEHGaD.js +1051 -0
  46. package/dist/deferred-index-build-BqmEHGaD.js.map +1 -0
  47. package/dist/{doctor-Cb2thZ8s.js → doctor-CUAAOFZm.js} +281 -89
  48. package/dist/doctor-CUAAOFZm.js.map +1 -0
  49. package/dist/ensure-collection-policies-Bb51V2OV.js +541 -0
  50. package/dist/ensure-collection-policies-Bb51V2OV.js.map +1 -0
  51. package/dist/ensure-collection-tables-egjGBjhv.js +532 -0
  52. package/dist/ensure-collection-tables-egjGBjhv.js.map +1 -0
  53. package/dist/{ensure-tables-Dhn9KM3B.js → ensure-tables-DMPWhJ6R.js} +180 -77
  54. package/dist/ensure-tables-DMPWhJ6R.js.map +1 -0
  55. package/dist/enum-labels-kept-Msq5gMcb.js +56 -0
  56. package/dist/enum-labels-kept-Msq5gMcb.js.map +1 -0
  57. package/dist/generate-drizzle-schema-DrA-YgXv.js +57 -0
  58. package/dist/generate-drizzle-schema-DrA-YgXv.js.map +1 -0
  59. package/dist/{generate-drizzle-schema-logic-BfzK7UQd.js → generate-drizzle-schema-logic-BaT0H7Gq.js} +29 -11
  60. package/dist/generate-drizzle-schema-logic-BaT0H7Gq.js.map +1 -0
  61. package/dist/generate-files-OoRJLEdk.js +199 -0
  62. package/dist/generate-files-OoRJLEdk.js.map +1 -0
  63. package/dist/generate-postgres-ddl-logic-B4k9djAV.js +152 -0
  64. package/dist/generate-postgres-ddl-logic-B4k9djAV.js.map +1 -0
  65. package/dist/{generated-schema-staleness-Di9c4ZxN.js → generated-schema-staleness-BWN_PsMi.js} +2 -2
  66. package/dist/{generated-schema-staleness-Di9c4ZxN.js.map → generated-schema-staleness-BWN_PsMi.js.map} +1 -1
  67. package/dist/generated-sql.d.ts +34 -0
  68. package/dist/history/HistoryService.d.ts +64 -5
  69. package/dist/history/ensure-history-table.d.ts +63 -4
  70. package/dist/index.d.ts +1 -0
  71. package/dist/index.es.js +139 -16738
  72. package/dist/index.es.js.map +1 -1
  73. package/dist/{introspect-db-logic-WMuAfxvw.js → introspect-db-logic-BCc1Jym2.js} +654 -353
  74. package/dist/introspect-db-logic-BCc1Jym2.js.map +1 -0
  75. package/dist/introspect-db-queries-BhhJg0b8.js +364 -0
  76. package/dist/introspect-db-queries-BhhJg0b8.js.map +1 -0
  77. package/dist/open-rebase-CAjWpPjs.js +20895 -0
  78. package/dist/open-rebase-CAjWpPjs.js.map +1 -0
  79. package/dist/open-rebase.d.ts +94 -0
  80. package/dist/pg-error-utils-Bs_Ue4wn.js +395 -0
  81. package/dist/pg-error-utils-Bs_Ue4wn.js.map +1 -0
  82. package/dist/{plan-schema-C0fxM8dY.js → plan-schema-CsNgK0qi.js} +279 -534
  83. package/dist/plan-schema-CsNgK0qi.js.map +1 -0
  84. package/dist/{policy-drift-DljYdrpW.js → policy-drift-BKC50y2p.js} +33 -9
  85. package/dist/policy-drift-BKC50y2p.js.map +1 -0
  86. package/dist/push-index-prebuild-C_qhyoJa.js +45 -0
  87. package/dist/push-index-prebuild-C_qhyoJa.js.map +1 -0
  88. package/dist/push-legacy-renames-5g9h3HOa.js +34 -0
  89. package/dist/push-legacy-renames-5g9h3HOa.js.map +1 -0
  90. package/dist/{generate-postgres-ddl-logic-Bt2d2mRH.js → render-ddl-CrfEe__B.js} +24 -157
  91. package/dist/render-ddl-CrfEe__B.js.map +1 -0
  92. package/dist/{rls-bootstrap-sql-B8EclDyM.js → rls-bootstrap-sql-Bd-hJk08.js} +125 -1101
  93. package/dist/rls-bootstrap-sql-Bd-hJk08.js.map +1 -0
  94. package/dist/{rls-enforcement-C6Xk0lA6.js → rls-enforcement-D7P4-ZYX.js} +138 -18
  95. package/dist/rls-enforcement-D7P4-ZYX.js.map +1 -0
  96. package/dist/{__vite-browser-external-BnuHet1e.js → rolldown-runtime-V7rFbMRe.js} +1 -8
  97. package/dist/schema/atlas-exclude.d.ts +42 -0
  98. package/dist/schema/auth-schema.d.ts +172 -2
  99. package/dist/schema/boot-ddl.d.ts +47 -0
  100. package/dist/schema/carved-out-migration.d.ts +5 -4
  101. package/dist/schema/classify-change.d.ts +29 -1
  102. package/dist/schema/collection-index.d.ts +45 -0
  103. package/dist/schema/column-plan-helpers.d.ts +38 -21
  104. package/dist/schema/deferred-index-build.d.ts +131 -0
  105. package/dist/schema/destructive-sql.d.ts +50 -2
  106. package/dist/schema/doctor-cli.js +110 -6
  107. package/dist/schema/doctor-cli.js.map +1 -1
  108. package/dist/schema/doctor-search-scale.d.ts +45 -0
  109. package/dist/schema/doctor.d.ts +53 -1
  110. package/dist/schema/ensure-collection-policies.d.ts +95 -35
  111. package/dist/schema/ensure-collection-tables.d.ts +56 -3
  112. package/dist/schema/enum-labels-kept.d.ts +26 -0
  113. package/dist/schema/generate-drizzle-schema.js +1 -1
  114. package/dist/schema/generate-files.d.ts +44 -0
  115. package/dist/schema/generate-next-step.d.ts +0 -13
  116. package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -5
  117. package/dist/schema/generate-postgres-ddl.js +10 -81
  118. package/dist/schema/generate-postgres-ddl.js.map +1 -1
  119. package/dist/schema/generate-schema-commit.d.ts +12 -0
  120. package/dist/schema/generated-schema-diff.d.ts +7 -0
  121. package/dist/schema/introspect-db-logic.d.ts +63 -0
  122. package/dist/schema/introspect-db-queries.d.ts +21 -2
  123. package/dist/schema/introspect-db-search.d.ts +22 -0
  124. package/dist/schema/introspect-db-storage.d.ts +83 -0
  125. package/dist/schema/introspect-db-structure.d.ts +10 -0
  126. package/dist/schema/introspect-db.js +29 -21
  127. package/dist/schema/introspect-db.js.map +1 -1
  128. package/dist/schema/migrate-baseline.d.ts +33 -0
  129. package/dist/schema/migration-post-process.d.ts +34 -0
  130. package/dist/schema/plan/diff-plan.d.ts +127 -1
  131. package/dist/schema/plan/plan-schema.d.ts +16 -8
  132. package/dist/schema/plan/render-ddl.d.ts +8 -1
  133. package/dist/schema/plan/types.d.ts +45 -11
  134. package/dist/schema/push-index-prebuild.d.ts +25 -0
  135. package/dist/schema/push-legacy-renames.d.ts +20 -0
  136. package/dist/schema/rls-bootstrap-sql.d.ts +15 -0
  137. package/dist/schema/undeclarable-constraints.d.ts +59 -0
  138. package/dist/search-column-BM-GV6vH.js +442 -0
  139. package/dist/search-column-BM-GV6vH.js.map +1 -0
  140. package/dist/security/policy-drift.d.ts +1 -1
  141. package/dist/security/rls-enforcement.d.ts +39 -4
  142. package/dist/services/BranchService.d.ts +29 -1
  143. package/dist/services/FetchService.d.ts +63 -12
  144. package/dist/services/PersistService.d.ts +15 -0
  145. package/dist/services/RelationService.d.ts +106 -3
  146. package/dist/services/cdc/CdcListener.d.ts +26 -10
  147. package/dist/services/cdc/identity-columns.d.ts +19 -0
  148. package/dist/services/cdc/trigger-cdc.d.ts +180 -18
  149. package/dist/services/channel-bus/PostgresChannelBus.d.ts +12 -7
  150. package/dist/services/channel-bus/index.d.ts +1 -1
  151. package/dist/services/channel-history.d.ts +32 -5
  152. package/dist/services/collection-helpers.d.ts +26 -1
  153. package/dist/services/field-viewer.d.ts +15 -1
  154. package/dist/services/pg-notify-listener.d.ts +95 -6
  155. package/dist/services/realtimeService.d.ts +467 -53
  156. package/dist/services/row-pipeline.d.ts +16 -9
  157. package/dist/services/socket-liveness.d.ts +85 -0
  158. package/dist/services/soft-delete.d.ts +12 -0
  159. package/dist/services/sql-script.d.ts +275 -0
  160. package/dist/services/vector-iterative-scan.d.ts +40 -0
  161. package/dist/services/write-depth.d.ts +22 -0
  162. package/dist/services/write-transaction-scope.d.ts +15 -3
  163. package/dist/socket-opt-ins.d.ts +64 -0
  164. package/dist/source-DB6xJv3p.js +873 -0
  165. package/dist/source-DB6xJv3p.js.map +1 -0
  166. package/dist/tsx-loader.d.ts +14 -0
  167. package/dist/utils/connection-string.d.ts +31 -0
  168. package/dist/utils/drizzle-conditions.d.ts +63 -3
  169. package/dist/utils/error-cause.d.ts +7 -0
  170. package/dist/utils/pg-error-utils.d.ts +2 -4
  171. package/dist/utils/result-rows.d.ts +10 -0
  172. package/dist/{vector-index-CMJKb3C9.js → vector-index-BFhyEaiz.js} +2 -2
  173. package/dist/{vector-index-CMJKb3C9.js.map → vector-index-BFhyEaiz.js.map} +1 -1
  174. package/dist/websocket-DUiiwQd2.js +1632 -0
  175. package/dist/websocket-DUiiwQd2.js.map +1 -0
  176. package/dist/websocket.d.ts +63 -18
  177. package/package.json +7 -7
  178. package/dist/BranchService-DGPL6G_C.js.map +0 -1
  179. package/dist/__vite-browser-external-BnuHet1e.js.map +0 -1
  180. package/dist/arg-Dni7MzLB.js.map +0 -1
  181. package/dist/backup-cli-24v4OlSp.js.map +0 -1
  182. package/dist/backup-service-HQ9GC4tN.js.map +0 -1
  183. package/dist/cli-errors-B8qHg02P.js +0 -798
  184. package/dist/cli-errors-B8qHg02P.js.map +0 -1
  185. package/dist/cli-flags-BglvpjHv.js.map +0 -1
  186. package/dist/cli-output-CNdMql-L.js +0 -47
  187. package/dist/cli-output-CNdMql-L.js.map +0 -1
  188. package/dist/collection-index-DdnsxiJ_.js +0 -286
  189. package/dist/collection-index-DdnsxiJ_.js.map +0 -1
  190. package/dist/column-plan-helpers-DF-8dTVa.js.map +0 -1
  191. package/dist/databasePoolManager-Bj5FbeAs.js.map +0 -1
  192. package/dist/doctor-Cb2thZ8s.js.map +0 -1
  193. package/dist/ensure-collection-policies-RHUcEp4v.js +0 -105
  194. package/dist/ensure-collection-policies-RHUcEp4v.js.map +0 -1
  195. package/dist/ensure-collection-tables-BEEjn5cn.js +0 -857
  196. package/dist/ensure-collection-tables-BEEjn5cn.js.map +0 -1
  197. package/dist/ensure-tables-Dhn9KM3B.js.map +0 -1
  198. package/dist/generate-drizzle-schema-logic-BfzK7UQd.js.map +0 -1
  199. package/dist/generate-drizzle-schema-yzY_BLhr.js +0 -123
  200. package/dist/generate-drizzle-schema-yzY_BLhr.js.map +0 -1
  201. package/dist/generate-postgres-ddl-logic-Bt2d2mRH.js.map +0 -1
  202. package/dist/introspect-db-logic-WMuAfxvw.js.map +0 -1
  203. package/dist/plan-schema-C0fxM8dY.js.map +0 -1
  204. package/dist/policy-drift-DljYdrpW.js.map +0 -1
  205. package/dist/rls-bootstrap-sql-B8EclDyM.js.map +0 -1
  206. package/dist/rls-enforcement-C6Xk0lA6.js.map +0 -1
  207. package/dist/source-Br7L7GOI.js +0 -410
  208. package/dist/source-Br7L7GOI.js.map +0 -1
@@ -89,22 +89,36 @@ export declare function diagnoseDbError(err: unknown, databaseUrl?: string): str
89
89
  * it resolved to and the cwd it resolved against, and then throws so the entry
90
90
  * point owns the exit code. Repeating its one-line summary underneath would
91
91
  * undo the "printed once" this whole path exists for.
92
+ *
93
+ * Whatever is printed has its connection-string passwords replaced (see
94
+ * `redactConnectionPasswords`): a driver or tool error can quote the URL it was
95
+ * given, and this line lands in terminals and CI logs.
92
96
  */
93
97
  export declare function reportCommandFailure(error: unknown): void;
94
98
  /**
95
99
  * `migrate apply` refusing because the database already has the schema.
96
100
  *
97
- * `42710` (duplicate_object) and `42P07` (duplicate_table) are what a migration
98
- * hits when boot-ensure — or a `db push` — has already provisioned the objects
99
- * it was going to create. Since boot-ensure provisions *every* production
101
+ * `42710` (duplicate_object), `42P07` (duplicate_table), `42701`
102
+ * (duplicate_column) and `42P06` (duplicate_schema) are what a migration hits
103
+ * when boot-ensure — or a `db push` — has already provisioned the objects it
104
+ * was going to create. Since boot-ensure provisions *every* production
100
105
  * database, this is the normal case rather than the exotic one, and the raw
101
106
  * failure (`pq: type "posts_status" already exists (42710)`, then `sql/migrate:
102
107
  * write revision: … current transaction is aborted`) names no way forward.
108
+ *
109
+ * `42701` is the everyday one in development: `rebase dev` adds a new
110
+ * column at boot, `db generate` writes the migration that adds it, and
111
+ * `db migrate` then finds it there. A column is named `table.column`.
103
112
  */
104
113
  export declare function parseAlreadyProvisioned(text: string): {
105
114
  object: string;
106
115
  code: string;
107
116
  } | null;
117
+ /**
118
+ * The migration Atlas was running when it failed: `from version "<v>"` in
119
+ * `sql/migrate: executing statement "…" from version "20261013201353": …`.
120
+ */
121
+ export declare function parseFailedMigrationVersion(text: string): string | null;
108
122
  /**
109
123
  * What to do about it: tell Atlas the database is already at a version.
110
124
  *
@@ -112,25 +126,56 @@ export declare function parseAlreadyProvisioned(text: string): {
112
126
  * ours — it writes the revision row Atlas reads, so every later `rebase db
113
127
  * migrate` is an ordinary one.
114
128
  */
115
- export declare function formatBaselineRemedy(version: string | null, object?: string): string;
129
+ export declare function formatBaselineRemedy(version: string | null, object?: string, failedVersion?: string | null): string;
130
+ /**
131
+ * Atlas's whole report when a connection was closed before it answered:
132
+ * `Error: EOF`, sometimes with the step in front (`Error: postgres: querying
133
+ * system variables: EOF`). The line names neither the database nor the
134
+ * connection, so on its own it reads like a crash.
135
+ */
136
+ export declare function parseConnectionEof(text: string): boolean;
137
+ /**
138
+ * What a closed connection means, and that running the command again is safe.
139
+ *
140
+ * On the managed development database it is almost always the connection
141
+ * limit. PGlite is one session behind a socket server that accepts only a few
142
+ * connections; a running `rebase dev` holds some, `atlas schema apply` opens
143
+ * two, and the one over the limit is closed unanswered. Measured: with the
144
+ * daemon's limit of four and three held, `db push --dry-run` failed with a
145
+ * bare `Error: EOF`; with two held it passed. The dev server's pool lets an
146
+ * idle connection go after 30 seconds (`idleTimeoutMillis` in connection.ts),
147
+ * which is why a later attempt usually works.
148
+ */
149
+ export declare function formatConnectionEofBanner(managed: boolean): string;
116
150
  /** `ALTER TABLE … SET NOT NULL` on a table that already holds rows (23502). */
117
151
  export declare function parseNotNullViolation(text: string): {
118
152
  table: string;
119
153
  column: string;
120
154
  } | null;
121
155
  /**
122
- * The three ways out, because there is no fourth.
156
+ * Whether the column that refused NOT NULL was being added by this push, read
157
+ * from the statement Atlas was running: `true` for `ADD COLUMN "<column>"`,
158
+ * `false` for any other statement that names it (`ALTER COLUMN … SET NOT
159
+ * NULL`), `null` when the error carried no statement.
160
+ */
161
+ export declare function notNullColumnIsNew(stderr: string, column: string): boolean | null;
162
+ /**
163
+ * The ways out, and only the ones that work for this column.
164
+ *
165
+ * A `defaultValue` backfills only a column the push is adding: PostgreSQL
166
+ * fills `ADD COLUMN … NOT NULL DEFAULT …` for every existing row, but `ALTER
167
+ * COLUMN … SET DEFAULT` touches no row that is already there, so for an
168
+ * existing column that remedy fails exactly as before. When the error does not
169
+ * say which it was (`isNew` null), the default is offered with that caveat.
123
170
  *
124
171
  * Boot-ensure handles this case — it adds the column nullable and sets NOT NULL
125
172
  * only when the table is empty — so a push that dies here is strictly worse
126
- * than the boot that would have run instead, and the developer deserves to be
127
- * told which of the three they want rather than left with `pq: … contains null
128
- * values (23502)` and no next step.
173
+ * than the boot that would have run instead.
129
174
  */
130
175
  export declare function formatNotNullViolationBanner(violation: {
131
176
  table: string;
132
177
  column: string;
133
- }, rowCount: number | null): string;
178
+ }, rowCount: number | null, isNew?: boolean | null): string;
134
179
  /** Atlas refusing to remove a label from an enum — a renamed `enum` option id. */
135
180
  export declare function parseEnumLabelDrop(text: string): {
136
181
  label: string;
@@ -148,6 +193,83 @@ export declare function formatEnumLabelDropBanner(drop: {
148
193
  label: string;
149
194
  enumType: string;
150
195
  }): string;
196
+ /**
197
+ * The statement Atlas was running when it failed, unescaped.
198
+ *
199
+ * Two spellings, one per phase: the apply quotes it
200
+ * (`executing statement "ALTER TABLE \"public\".\"people\" …;": pq: …`), and
201
+ * the dry-run's analysis does not
202
+ * (`analyzing plan: executing statement: ALTER TABLE "public"."people" …;: pq: …`).
203
+ */
204
+ export declare function parseFailedStatement(text: string): string | null;
205
+ /** `ALTER TABLE "public"."people" …` → `{ schema: "public", table: "people" }`. */
206
+ export declare function failedStatementTable(statement: string): {
207
+ schema?: string;
208
+ table: string;
209
+ } | null;
210
+ /** A generated column standing in the way of a retype, as the catalogue has it. */
211
+ export interface GeneratedColumnBlocker {
212
+ schema: string;
213
+ table: string;
214
+ /** The generated column. */
215
+ column: string;
216
+ /** The column it reads, which the statement retypes. */
217
+ reads: string;
218
+ }
219
+ /**
220
+ * PostgreSQL refusing to retype a column a `GENERATED ALWAYS AS … STORED`
221
+ * expression reads (0A000). `db push` moves Rebase's own search columns out of
222
+ * the way before the apply; this is what is left when it could not.
223
+ */
224
+ export declare function parseGeneratedColumnRefusal(text: string): {
225
+ statement: string | null;
226
+ } | null;
227
+ /**
228
+ * What to do when a generated column stops a retype.
229
+ *
230
+ * A collection's own search column should never reach this — `db push` drops
231
+ * it before the apply and rebuilds it after — so seeing one named here means
232
+ * that machinery missed it, which is a bug worth a report. Any other generated
233
+ * column is somebody's, with an expression Rebase holds no copy of.
234
+ */
235
+ export declare function formatGeneratedColumnRefusalBanner(refusal: {
236
+ statement: string | null;
237
+ }, blockers: GeneratedColumnBlocker[]): string;
238
+ /**
239
+ * PostgreSQL refusing a retype it has no implicit cast for (42804): `string` →
240
+ * `number`, `time` → `date`, an array back to a string. Atlas reports it from
241
+ * the dry-run's analysis as well as from the apply, so without this a
242
+ * `--dry-run` died with the raw error and showed no plan at all.
243
+ */
244
+ export declare function parseUncastableRetype(text: string): {
245
+ column: string;
246
+ type: string;
247
+ statement: string | null;
248
+ } | null;
249
+ /** The `ALTER … USING` a developer would run, and the other ways past it. Boot's drift report says the same. */
250
+ export declare function formatUncastableRetypeBanner(refusal: {
251
+ column: string;
252
+ type: string;
253
+ statement: string | null;
254
+ }): string;
255
+ /**
256
+ * A unique constraint or index PostgreSQL could not build because the rows
257
+ * already repeat a value (23505). The DETAIL naming the value does not survive
258
+ * Atlas, so the duplicates are read back from the table.
259
+ */
260
+ export declare function parseUniqueBuildFailure(text: string): {
261
+ index: string;
262
+ statement: string | null;
263
+ columns: string[];
264
+ } | null;
265
+ export declare function formatUniqueBuildFailureBanner(failure: {
266
+ index: string;
267
+ statement: string | null;
268
+ columns: string[];
269
+ }, duplicates: {
270
+ values: string;
271
+ count: number;
272
+ }[]): string;
151
273
  /**
152
274
  * A hand-written generated column reading a column the plan wants to retype or
153
275
  * drop.
@@ -181,4 +303,6 @@ export declare function diagnoseAtlasFailure(context: {
181
303
  databaseUrl?: string;
182
304
  /** The newest migration version on disk, named in the baseline remedy. */
183
305
  latestMigrationVersion?: string | null;
306
+ /** DATABASE_URL is the managed development database (PGlite). */
307
+ managedDatabase?: boolean;
184
308
  }): Promise<string | null>;
@@ -1,7 +1,8 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  __createRequire(import.meta.url);
3
- import { a as __toESM } from "./__vite-browser-external-BnuHet1e.js";
4
- import { t as require_arg } from "./arg-Dni7MzLB.js";
3
+ import { i as __toESM } from "./rolldown-runtime-V7rFbMRe.js";
4
+ import { n as require_arg } from "./cli-prompt-egtNKkZl.js";
5
+ import { suggestNearMiss } from "@rebasepro/utils";
5
6
  //#region src/cli-flags.ts
6
7
  var import_arg = /* @__PURE__ */ __toESM(require_arg(), 1);
7
8
  /**
@@ -54,7 +55,10 @@ var DRIVER_FLAG_SPECS = {
54
55
  "--collections": String,
55
56
  "-c": "--collections"
56
57
  },
57
- "db migrate": { "--baseline": String },
58
+ "db migrate": {
59
+ "--baseline": String,
60
+ "--refuse-destructive": Boolean
61
+ },
58
62
  "schema generate": {
59
63
  "--collections": String,
60
64
  "-c": "--collections",
@@ -128,11 +132,57 @@ function assertKnownFlags(domain, subcommand, args) {
128
132
  ...spec
129
133
  }, { argv: args.slice(2) });
130
134
  } catch (err) {
131
- if (err instanceof Error && err.code === "ARG_UNKNOWN_OPTION") throw new Error(`${err.message} — run \`rebase ${domain} --help\` for the options \`${domain} ${subcommand}\` takes.`);
135
+ const unknown = unknownFlagIn(err);
136
+ if (unknown !== null && err instanceof Error) {
137
+ const suggestion = closestFlag(unknown, {
138
+ ...RELAYED_FLAGS,
139
+ ...spec
140
+ });
141
+ throw new Error(`${err.message}${suggestion ? ` (did you mean ${suggestion}?)` : ""} — run \`rebase ${domain} --help\` for the options \`${domain} ${subcommand}\` takes.`);
142
+ }
132
143
  throw err;
133
144
  }
134
145
  }
146
+ /** The flag `arg` refused as undeclared, or `null` for any other failure. */
147
+ function unknownFlagIn(err) {
148
+ if (!(err instanceof Error) || !("code" in err) || err.code !== "ARG_UNKNOWN_OPTION") return null;
149
+ return /option: (\S+)$/.exec(err.message)?.[1] ?? null;
150
+ }
151
+ /** The declared long flag `typed` is one edit away from, if there is one. */
152
+ function closestFlag(typed, spec) {
153
+ const name = typed.split("=")[0];
154
+ return suggestNearMiss(Object.keys(spec).filter((flag) => flag.startsWith("--")), name);
155
+ }
156
+ /**
157
+ * Parse a command that owns its argument handling, refusing what it does not
158
+ * declare.
159
+ *
160
+ * `db backup`, `db restore` and `db backups list` parsed permissively, so an
161
+ * undeclared flag became a positional and was ignored: `db restore <dump>
162
+ * --targt-db x --create-db --yes` dropped the misspelled target and restored
163
+ * into the live database. A typo is refused here before anything runs, naming
164
+ * the declared flag it is one edit from, or every flag the command takes when
165
+ * none is that close.
166
+ *
167
+ * @param argv the words after the command, e.g. `rawArgs.slice(2)`.
168
+ * @param command the command as typed, for the message: `"db restore"`.
169
+ */
170
+ function parseCommandFlags(spec, argv, command) {
171
+ const full = {
172
+ ...RELAYED_FLAGS,
173
+ ...spec
174
+ };
175
+ try {
176
+ return (0, import_arg.default)(full, { argv });
177
+ } catch (err) {
178
+ const unknown = unknownFlagIn(err);
179
+ if (unknown === null) throw err;
180
+ const suggestion = closestFlag(unknown, full);
181
+ const flags = Object.keys(spec).filter((flag) => flag.startsWith("--"));
182
+ throw new Error(`\`rebase ${command}\` has no option ${unknown}` + (suggestion ? ` — did you mean ${suggestion}?` : ` — it takes ${flags.join(", ")}.`) + ` Nothing was run. See \`rebase ${command} --help\`.`);
183
+ }
184
+ }
135
185
  //#endregion
136
- export { collectionsPathIn as n, parseDriverLine as r, assertKnownFlags as t };
186
+ export { parseDriverLine as a, parseCommandFlags as i, assertKnownFlags as n, collectionsPathIn as r, RELAYED_FLAGS as t };
137
187
 
138
- //# sourceMappingURL=cli-flags-BglvpjHv.js.map
188
+ //# sourceMappingURL=cli-flags-DnPHXjRH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-flags-DnPHXjRH.js","names":[],"sources":["../src/cli-flags.ts"],"sourcesContent":["/**\n * The flags each driver command takes, in one place, and the check that\n * enforces them.\n *\n * Every parser in `cli.ts` runs `arg(..., { permissive: true })`, which does not\n * mean \"be lenient\" — it means **an undeclared flag becomes a positional**. So\n * `rebase db push --alow-destructive` did not fail: the typo landed in `_`, the\n * push ran with the destructive gate still closed, and the developer read the\n * refusal as Rebase ignoring the flag they had just typed. `rebase schema\n * generate --ouput src/schema.ts` was worse — it wrote the default path and\n * said nothing, so the next build compiled a file nobody had regenerated.\n *\n * The check has to live at the entry point rather than in those parsers, and\n * that is not a detail: `db push` and `db generate` re-enter `schemaCommand`\n * and `generatePostgresDdlCommand` with the *db* line, so a strict parser\n * inside either of them would reject `--allow-destructive` on a line where it\n * is correct. One validation, once, against the spec for the command the user\n * actually named; the inner parsers keep reading an already-validated line.\n *\n * Commands with their own argument handling — `db branch` (`unexpectedBranchArgs`),\n * `db backup`, `db restore`, `db backups` — are deliberately absent: they own\n * their spec, and a second list here would be one more thing to keep in step.\n * An absent entry is \"not checked here\", never \"takes nothing\".\n */\nimport arg from \"arg\";\nimport { suggestNearMiss } from \"@rebasepro/utils\";\n\n/**\n * Flags that reach this process on a line it did not compose.\n *\n * `rebase db …` hands the driver the user's whole line: the CLI *reads*\n * `--database-url` and `--docker` to resolve the database and then relays them\n * verbatim, and `--debug` is what `bin/rebase.js` prints after every failure as\n * the thing to re-run with. Rejecting any of the three would make the driver\n * refuse commands the CLI documents.\n */\nexport const RELAYED_FLAGS = {\n \"--database-url\": String,\n \"--docker\": Boolean,\n \"--debug\": Boolean,\n \"--help\": Boolean,\n \"-h\": \"--help\"\n} satisfies arg.Spec;\n\n/**\n * Parse a driver command's line — `[\"db\", \"<subcommand>\", …]` — with the\n * relayed flags declared alongside the command's own.\n *\n * Every driver parser is permissive, and an undeclared flag in a permissive\n * parse is a positional. The positionals are what `db migrate` hands\n * `atlas migrate apply`, what `db generate` names its migration after and\n * which backup `db restore` restores, so a relayed flag left undeclared was\n * read as one of those: `rebase db migrate --docker` died on Atlas's\n * `unknown flag: --docker` after it had already written the auth schema.\n */\nexport function parseDriverLine<S extends arg.Spec>(\n spec: S,\n args: string[]\n): arg.Result<typeof RELAYED_FLAGS & S> {\n return arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2), permissive: true });\n}\n\n/** Keyed by `\"<domain> <subcommand>\"`, the way the user types it. */\nexport const DRIVER_FLAG_SPECS: Record<string, arg.Spec> = {\n \"db push\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--dry-run\": Boolean,\n \"--allow-destructive\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n },\n \"db generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\"\n },\n // Bare positionals still pass through to `atlas migrate apply`, which takes\n // an optional amount; flags do not, apart from `--baseline`.\n //\n // `--baseline <version>` is the escape hatch for the normal case, not an\n // exotic one: every Rebase boot ensures the schema, so a production\n // database has the tables before its first migration ever runs, and\n // `migrate apply` then dies on `type \"…\" already exists (42710)`. It maps\n // onto Atlas's own `migrate apply --baseline`, which writes the revision\n // row Atlas reads — no ledger of ours.\n //\n // `--refuse-destructive` is opt-in: it dry-runs the pending files and exits\n // 1, applying nothing, when one drops or narrows data — the gate `db push`\n // has always had, for the path that had none.\n \"db migrate\": {\n \"--baseline\": String,\n \"--refuse-destructive\": Boolean\n },\n \"schema generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--watch\": Boolean,\n \"-w\": \"--watch\"\n },\n \"schema introspect\": {\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--force\": Boolean,\n \"-f\": \"--force\",\n \"--schema\": String\n },\n \"schema stale\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--fix\": Boolean\n }\n};\n\n/**\n * One destination flag, two spellings, everywhere.\n *\n * `--out` is the primary on `rebase build`, an alias on `generate-sdk`, `db\n * backup` and `cloud env pull`, and was refused outright by the three `schema`\n * commands — so the spelling a user learned on one command was an\n * \"unknown or unexpected option\" on the next. Neither name can be retired (both\n * are shipped), so both are accepted, and {@link assertOutputAliasesPaired}\n * makes that the rule rather than a habit.\n */\nexport const OUTPUT_FLAG_ALIASES = [\"--out\", \"--output\"] as const;\n\n/**\n * Every spec that names one of the pair names both.\n *\n * Exported so the CLI's own specs can be held to it too: the drift this fixes\n * ran across two packages, and a check that only reads this file would let the\n * next `--out`-only command through.\n */\nexport function assertOutputAliasesPaired(specs: Record<string, arg.Spec>): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const present = OUTPUT_FLAG_ALIASES.filter(flag => flag in spec);\n if (present.length === 0 || present.length === OUTPUT_FLAG_ALIASES.length) continue;\n const missing = OUTPUT_FLAG_ALIASES.filter(flag => !(flag in spec));\n problems.push(`\\`${command}\\` takes ${present.join(\", \")} but not ${missing.join(\", \")}`);\n }\n return problems;\n}\n\n/**\n * The `--collections` path the user typed, or `null` if they typed none.\n *\n * Read once, at the entry point, because every command that takes it re-enters\n * the generators with the same line and each of them resolved it again — which\n * is how \"Collections path not found\" came to be printed four times before the\n * real output, and how a path that does not exist got as far as *writing* an\n * empty schema.\n *\n * Permissive, and it has to be: {@link assertKnownFlags} has already judged the\n * line, and `db push` carries flags the `--collections` spec does not name.\n */\nexport function collectionsPathIn(args: string[]): string | null {\n try {\n const parsed = arg(\n { \"--collections\": String, \"-c\": \"--collections\" },\n { argv: args.slice(2), permissive: true }\n );\n\n return parsed[\"--collections\"] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * The long flags a `--help` usage line documents.\n *\n * `\"rebase db push [--collections <dir>] [--dry-run] …\"` → `[\"--collections\",\n * \"--dry-run\"]`. Placeholders (`<dir>`) and the alternation inside a positional\n * (`<create|list|switch>`) are not flags and are not returned.\n */\nexport function flagsInUsage(usage: string): string[] {\n return [...new Set(usage.match(/--[a-z][a-z0-9-]*/g) ?? [])];\n}\n\n/**\n * Every flag the help documents is accepted, and every flag accepted is documented.\n *\n * The drift this catches shipped: `rebase db push --help` has printed\n * `[--dry-run]` since the flag was written, `DRIVER_FLAG_SPECS[\"db push\"]` never\n * listed it, and {@link assertKnownFlags} — added later to stop typos being\n * swallowed — turned the documented flag into `unknown or unexpected option`.\n * The only way to see a push's SQL was to trip the destructive gate, which is\n * the exact problem `--dry-run` was written to solve. Worse in a project on an\n * older driver, whose permissive parser *applied* the schema on that line.\n *\n * Two hand-maintained lists in two packages cannot be kept in step by care, so\n * they are held to each other instead: `usages` is keyed the way\n * {@link DRIVER_FLAG_SPECS} is (`\"db push\"`), and comes from the CLI's own help\n * pages. A key in only one of the two is not this function's business — the\n * help covers commands that parse their own lines (`db branch`, `db backup`),\n * and an absent spec entry means \"not checked here\".\n *\n * Aliases (`\"-c\": \"--collections\"`, `\"--out\": \"--output\"`) need no line of their\n * own: they are spellings of a documented flag. Neither do {@link RELAYED_FLAGS},\n * which every driver command accepts because the CLI relays them.\n */\nexport function assertSpecMatchesUsage(\n specs: Record<string, arg.Spec>,\n usages: Record<string, string>\n): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const usage = usages[command];\n if (usage === undefined) continue;\n\n const documented = flagsInUsage(usage);\n const accepted = Object.entries(spec);\n // An alias resolves to the flag it spells; only the target needs a line.\n const canonical = new Set(\n accepted\n .map(([flag, kind]) => (typeof kind === \"string\" ? kind : flag))\n .filter(flag => flag.startsWith(\"--\"))\n );\n\n for (const flag of documented) {\n if (flag in spec || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` documents ${flag} in its usage line but the spec rejects it`);\n }\n for (const flag of canonical) {\n if (documented.includes(flag) || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` accepts ${flag} but no usage line documents it`);\n }\n }\n return problems;\n}\n\n/**\n * Reject a flag the named command does not take.\n *\n * `args` is the driver's whole line — `[\"db\", \"push\", …]` — so the flags are\n * read from `args.slice(2)`, past the two command words.\n *\n * Throws rather than exiting: `runPluginCommand`'s caller already turns a\n * thrown error into one red line and exit 1, and a thrown error is what the\n * tests can see.\n */\nexport function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void {\n if (!subcommand) return;\n const spec = DRIVER_FLAG_SPECS[`${domain} ${subcommand}`];\n if (!spec) return;\n\n try {\n arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2) });\n } catch (err) {\n const unknown = unknownFlagIn(err);\n if (unknown !== null && err instanceof Error) {\n const suggestion = closestFlag(unknown, { ...RELAYED_FLAGS, ...spec });\n throw new Error(\n `${err.message}${suggestion ? ` (did you mean ${suggestion}?)` : \"\"} — run ` +\n `\\`rebase ${domain} --help\\` for the options \\`${domain} ${subcommand}\\` takes.`\n );\n }\n throw err;\n }\n}\n\n/** The flag `arg` refused as undeclared, or `null` for any other failure. */\nfunction unknownFlagIn(err: unknown): string | null {\n if (!(err instanceof Error) || !(\"code\" in err) || err.code !== \"ARG_UNKNOWN_OPTION\") return null;\n // arg's wording: `unknown or unexpected option: --targt-db`.\n return /option: (\\S+)$/.exec(err.message)?.[1] ?? null;\n}\n\n/** The declared long flag `typed` is one edit away from, if there is one. */\nfunction closestFlag(typed: string, spec: arg.Spec): string | undefined {\n const name = typed.split(\"=\")[0];\n return suggestNearMiss(Object.keys(spec).filter(flag => flag.startsWith(\"--\")), name);\n}\n\n/**\n * Parse a command that owns its argument handling, refusing what it does not\n * declare.\n *\n * `db backup`, `db restore` and `db backups list` parsed permissively, so an\n * undeclared flag became a positional and was ignored: `db restore <dump>\n * --targt-db x --create-db --yes` dropped the misspelled target and restored\n * into the live database. A typo is refused here before anything runs, naming\n * the declared flag it is one edit from, or every flag the command takes when\n * none is that close.\n *\n * @param argv the words after the command, e.g. `rawArgs.slice(2)`.\n * @param command the command as typed, for the message: `\"db restore\"`.\n */\nexport function parseCommandFlags<S extends arg.Spec>(\n spec: S,\n argv: string[],\n command: string\n): arg.Result<typeof RELAYED_FLAGS & S> {\n const full = { ...RELAYED_FLAGS, ...spec };\n try {\n return arg(full, { argv });\n } catch (err) {\n const unknown = unknownFlagIn(err);\n if (unknown === null) throw err;\n const suggestion = closestFlag(unknown, full);\n const flags = Object.keys(spec).filter(flag => flag.startsWith(\"--\"));\n throw new Error(\n `\\`rebase ${command}\\` has no option ${unknown}` +\n (suggestion ? ` — did you mean ${suggestion}?` : ` — it takes ${flags.join(\", \")}.`) +\n ` Nothing was run. See \\`rebase ${command} --help\\`.`\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,IAAa,gBAAgB;CACzB,kBAAkB;CAClB,YAAY;CACZ,WAAW;CACX,UAAU;CACV,MAAM;AACV;;;;;;;;;;;;AAaA,SAAgB,gBACZ,MACA,MACoC;CACpC,QAAA,GAAA,WAAA,QAAA,CAAW;EAAE,GAAG;EAAe,GAAG;CAAK,GAAG;EAAE,MAAM,KAAK,MAAM,CAAC;EAAG,YAAY;CAAK,CAAC;AACvF;;AAGA,IAAa,oBAA8C;CACvD,WAAW;EACP,iBAAiB;EACjB,MAAM;EACN,aAAa;EACb,uBAAuB;EACvB,SAAS;EACT,MAAM;CACV;CACA,eAAe;EACX,iBAAiB;EACjB,MAAM;CACV;CAcA,cAAc;EACV,cAAc;EACd,wBAAwB;CAC5B;CACA,mBAAmB;EACf,iBAAiB;EACjB,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,WAAW;EACX,MAAM;CACV;CACA,qBAAqB;EACjB,YAAY;EACZ,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,MAAM;EACN,WAAW;EACX,MAAM;EACN,YAAY;CAChB;CACA,gBAAgB;EACZ,iBAAiB;EACjB,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,SAAS;CACb;AACJ;;;;;;;;;;;;;AA4CA,SAAgB,kBAAkB,MAA+B;CAC7D,IAAI;EAMA,QAAA,GAAA,WAAA,QAAA,CAJI;GAAE,iBAAiB;GAAQ,MAAM;EAAgB,GACjD;GAAE,MAAM,KAAK,MAAM,CAAC;GAAG,YAAY;EAAK,CAGrC,CAAA,CAAO,oBAAoB;CACtC,QAAQ;EACJ,OAAO;CACX;AACJ;;;;;;;;;;;AA2EA,SAAgB,iBAAiB,QAAgB,YAAgC,MAAsB;CACnG,IAAI,CAAC,YAAY;CACjB,MAAM,OAAO,kBAAkB,GAAG,OAAO,GAAG;CAC5C,IAAI,CAAC,MAAM;CAEX,IAAI;EACA,CAAA,GAAA,WAAA,QAAA,CAAI;GAAE,GAAG;GAAe,GAAG;EAAK,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;CAC9D,SAAS,KAAK;EACV,MAAM,UAAU,cAAc,GAAG;EACjC,IAAI,YAAY,QAAQ,eAAe,OAAO;GAC1C,MAAM,aAAa,YAAY,SAAS;IAAE,GAAG;IAAe,GAAG;GAAK,CAAC;GACrE,MAAM,IAAI,MACN,GAAG,IAAI,UAAU,aAAa,kBAAkB,WAAW,MAAM,GAAG,kBACxD,OAAO,8BAA8B,OAAO,GAAG,WAAW,UAC1E;EACJ;EACA,MAAM;CACV;AACJ;;AAGA,SAAS,cAAc,KAA6B;CAChD,IAAI,EAAE,eAAe,UAAU,EAAE,UAAU,QAAQ,IAAI,SAAS,sBAAsB,OAAO;CAE7F,OAAO,iBAAiB,KAAK,IAAI,OAAO,CAAC,GAAG,MAAM;AACtD;;AAGA,SAAS,YAAY,OAAe,MAAoC;CACpE,MAAM,OAAO,MAAM,MAAM,GAAG,CAAC,CAAC;CAC9B,OAAO,gBAAgB,OAAO,KAAK,IAAI,CAAC,CAAC,QAAO,SAAQ,KAAK,WAAW,IAAI,CAAC,GAAG,IAAI;AACxF;;;;;;;;;;;;;;;AAgBA,SAAgB,kBACZ,MACA,MACA,SACoC;CACpC,MAAM,OAAO;EAAE,GAAG;EAAe,GAAG;CAAK;CACzC,IAAI;EACA,QAAA,GAAA,WAAA,QAAA,CAAW,MAAM,EAAE,KAAK,CAAC;CAC7B,SAAS,KAAK;EACV,MAAM,UAAU,cAAc,GAAG;EACjC,IAAI,YAAY,MAAM,MAAM;EAC5B,MAAM,aAAa,YAAY,SAAS,IAAI;EAC5C,MAAM,QAAQ,OAAO,KAAK,IAAI,CAAC,CAAC,QAAO,SAAQ,KAAK,WAAW,IAAI,CAAC;EACpE,MAAM,IAAI,MACN,YAAY,QAAQ,mBAAmB,aACtC,aAAa,mBAAmB,WAAW,KAAK,eAAe,MAAM,KAAK,IAAI,EAAE,MACjF,kCAAkC,QAAQ,WAC9C;CACJ;AACJ"}
@@ -127,3 +127,18 @@ export declare function assertSpecMatchesUsage(specs: Record<string, arg.Spec>,
127
127
  * tests can see.
128
128
  */
129
129
  export declare function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void;
130
+ /**
131
+ * Parse a command that owns its argument handling, refusing what it does not
132
+ * declare.
133
+ *
134
+ * `db backup`, `db restore` and `db backups list` parsed permissively, so an
135
+ * undeclared flag became a positional and was ignored: `db restore <dump>
136
+ * --targt-db x --create-db --yes` dropped the misspelled target and restored
137
+ * into the live database. A typo is refused here before anything runs, naming
138
+ * the declared flag it is one edit from, or every flag the command takes when
139
+ * none is that close.
140
+ *
141
+ * @param argv the words after the command, e.g. `rawArgs.slice(2)`.
142
+ * @param command the command as typed, for the message: `"db restore"`.
143
+ */
144
+ export declare function parseCommandFlags<S extends arg.Spec>(spec: S, argv: string[], command: string): arg.Result<typeof RELAYED_FLAGS & S>;
@@ -1,5 +1,6 @@
1
1
  import type { GeneratedColumnDependency } from "./schema/generated-column-conflicts.js";
2
2
  import { type ExistingColumnType } from "./schema/destructive-sql.js";
3
+ import { type ExistingConstraint } from "./schema/undeclarable-constraints.js";
3
4
  import type { CollectionConfig } from "@rebasepro/types";
4
5
  /**
5
6
  * Why is a dependency's binary missing — never installed, or installed with its
@@ -84,6 +85,45 @@ export declare function resolveLocalBin(binName: string): string | null;
84
85
  export declare function getTableIncludesFromCollections(allCollections: CollectionConfig[]): Promise<string[]>;
85
86
  export declare function getTableIncludes(collectionsPath: string): Promise<string[]>;
86
87
  export declare function loadCollectionsForCli(collectionsPath: string): Promise<CollectionConfig[]>;
88
+ type PgClient = import("pg").Client;
89
+ /**
90
+ * Run one step on this process's connection to the app database.
91
+ *
92
+ * Every step leaves the session as it found it, which is what a connection of
93
+ * its own used to guarantee by being closed. None of them sets anything for
94
+ * the session — `SET LOCAL` inside their own transaction, or `RESET` — and one
95
+ * that fails part-way through a transaction it opened is rolled back here, so
96
+ * the next step does not meet `current transaction is aborted`.
97
+ *
98
+ * @param options.connectionTimeoutMillis applies only when this call is the one
99
+ * that connects.
100
+ */
101
+ export declare function withAppClient<T>(databaseUrl: string, step: (client: PgClient) => Promise<T>, options?: {
102
+ connectionTimeoutMillis?: number;
103
+ }): Promise<T>;
104
+ /** Close every connection {@link withAppClient} opened. Called once, as the command ends. */
105
+ export declare function closeAppClients(): Promise<void>;
106
+ /**
107
+ * Names the empty database Atlas plans against, instead of `<db>_dev_diff`.
108
+ *
109
+ * The derived one is made with `CREATE DATABASE` beside the real database,
110
+ * which assumes a server that holds more than one. PGlite — the managed
111
+ * development database — serves exactly one: the CREATE succeeds and creates
112
+ * nothing, so Atlas connected straight back to the database it was comparing
113
+ * and refused it as "not clean". `rebase db push` on the managed database now
114
+ * starts a second, throwaway PGlite and names it here. Anyone can name their
115
+ * own the same way; a named database is neither created nor dropped.
116
+ */
117
+ export declare const ATLAS_DEV_URL_ENV = "REBASE_ATLAS_DEV_URL";
118
+ /**
119
+ * The database Atlas replays the desired schema into: the one
120
+ * {@link ATLAS_DEV_URL_ENV} names (`named: true` — not ours to create or
121
+ * drop), else `<db>_dev_diff`.
122
+ */
123
+ export declare function atlasDevDatabaseUrl(databaseUrl: string, env: Readonly<Record<string, string | undefined>>): {
124
+ url: string;
125
+ named: boolean;
126
+ };
87
127
  export declare function getDevDatabaseUrl(databaseUrl: string): string;
88
128
  /**
89
129
  * Create the scratch database Atlas plans against, and say so when we cannot.
@@ -127,10 +167,10 @@ export declare function dropDevDatabase(databaseUrl: string, devDatabaseUrl: str
127
167
  /**
128
168
  * The generated SQL for the project's `search` blocks, if it has any.
129
169
  *
130
- * @param drizzleDir directory holding the generated SQL. Defaults to `drizzle`
131
- * under the working directory.
170
+ * @param sqlDir directory holding the generated SQL. Defaults to
171
+ * `.rebase/sql` under the working directory.
132
172
  */
133
- export declare function readSearchDdl(drizzleDir?: string): string;
173
+ export declare function readSearchDdl(sqlDir?: string): string;
134
174
  /**
135
175
  * Bring the search column, its index and their helpers up to date.
136
176
  *
@@ -144,7 +184,7 @@ export declare function readSearchDdl(drizzleDir?: string): string;
144
184
  * silently pushing a schema whose search column never appeared is how a
145
185
  * collection ends up with search configured, no error anywhere, and no results.
146
186
  */
147
- export declare function applySearchDdl(databaseUrl: string, drizzleDir?: string): Promise<void>;
187
+ export declare function applySearchDdl(databaseUrl: string, sqlDir?: string): Promise<void>;
148
188
  /**
149
189
  * Glob patterns keeping Atlas away from the search objects.
150
190
  *
@@ -181,10 +221,10 @@ export declare function dropGeneratedColumns(databaseUrl: string, statements: st
181
221
  /**
182
222
  * The generated SQL for the project's `vector` properties, if it has any.
183
223
  *
184
- * @param drizzleDir directory holding the generated SQL. Defaults to `drizzle`
185
- * under the working directory.
224
+ * @param sqlDir directory holding the generated SQL. Defaults to
225
+ * `.rebase/sql` under the working directory.
186
226
  */
187
- export declare function readVectorDdl(drizzleDir?: string): string;
227
+ export declare function readVectorDdl(sqlDir?: string): string;
188
228
  /**
189
229
  * Install pgvector and bring the vector columns and their ANN indexes up to
190
230
  * date.
@@ -200,7 +240,7 @@ export declare function readVectorDdl(drizzleDir?: string): string;
200
240
  * appeared is how a project ends up with vector search configured, no error
201
241
  * anywhere, and no results.
202
242
  */
203
- export declare function applyVectorDdl(databaseUrl: string, drizzleDir?: string): Promise<void>;
243
+ export declare function applyVectorDdl(databaseUrl: string, sqlDir?: string): Promise<void>;
204
244
  /**
205
245
  * Glob patterns keeping Atlas away from the vector objects.
206
246
  *
@@ -212,10 +252,10 @@ export declare function getVectorExcludes(collectionsPath: string): Promise<stri
212
252
  * The generated SQL for the project's `autoValue: "on_update"` properties, if
213
253
  * it has any.
214
254
  *
215
- * @param drizzleDir directory holding the generated SQL. Defaults to `drizzle`
216
- * under the working directory.
255
+ * @param sqlDir directory holding the generated SQL. Defaults to
256
+ * `.rebase/sql` under the working directory.
217
257
  */
218
- export declare function readTriggersDdl(drizzleDir?: string): string;
258
+ export declare function readTriggersDdl(sqlDir?: string): string;
219
259
  /**
220
260
  * Install the `updated_at` trigger function and bind it to every column that
221
261
  * asked for one.
@@ -230,7 +270,7 @@ export declare function readTriggersDdl(drizzleDir?: string): string;
230
270
  * appeared is how `updated_at` ends up silently stale for every writer that is
231
271
  * not the driver, which is the whole reason the trigger exists.
232
272
  */
233
- export declare function applyTriggersDdl(databaseUrl: string, drizzleDir?: string): Promise<void>;
273
+ export declare function applyTriggersDdl(databaseUrl: string, sqlDir?: string): Promise<void>;
234
274
  /** @see getSearchExcludes */
235
275
  export declare function getTriggerExcludes(collectionsPath: string): Promise<string[]>;
236
276
  /**
@@ -238,15 +278,21 @@ export declare function getTriggerExcludes(collectionsPath: string): Promise<str
238
278
  * catalogs. Separated from {@link getTableExcludes} so its failure mode can
239
279
  * be handled explicitly (fail closed) and so tests can inject a stub.
240
280
  */
281
+ /** An index as the catalogue names it: its schema, its table and its own name. */
282
+ export interface ExistingIndex {
283
+ schema: string;
284
+ table: string;
285
+ index: string;
286
+ }
241
287
  /**
242
- * Every index Postgres holds on a table Rebase manages, as
243
- * `schema.table.index`.
288
+ * Every index Postgres holds on a table, by its parts — never joined with `.`,
289
+ * which a name may itself contain.
244
290
  *
245
291
  * Constraint-backed indexes are left out: a `PRIMARY KEY` or a `UNIQUE` is a
246
292
  * *constraint* to Atlas, diffed from the constraint declaration, and naming its
247
293
  * index in an exclude would shield the constraint itself.
248
294
  */
249
- export declare function queryExistingIndexes(databaseUrl: string): Promise<string[]>;
295
+ export declare function queryExistingIndexes(databaseUrl: string): Promise<ExistingIndex[]>;
250
296
  /**
251
297
  * Glob patterns keeping Atlas away from indexes that are not Rebase's.
252
298
  *
@@ -273,13 +319,35 @@ export declare function queryExistingIndexes(databaseUrl: string): Promise<strin
273
319
  *
274
320
  * Three-part `schema.table.index`, never two: a two-part pattern reads as a
275
321
  * *table* named `<index>` in a *schema* named `<table>`, matches nothing, and
276
- * reports no error — the trap already recorded for the search excludes.
322
+ * reports no error — the trap already recorded for the search excludes. And
323
+ * spelled by `atlasExcludePattern`: a raw `orders_idx[v1]` is a glob that
324
+ * matches `orders_idxv`, so that index was dropped with no prompt.
277
325
  */
278
326
  export declare function getForeignIndexExcludes(databaseUrl: string, collectionsPath: string, deps?: {
279
- queryExistingIndexes?: (databaseUrl: string) => Promise<string[]>;
327
+ queryExistingIndexes?: (databaseUrl: string) => Promise<ExistingIndex[]>;
280
328
  getManagedIndexNames?: (collectionsPath: string) => Promise<Set<string>>;
281
329
  }): Promise<string[]>;
282
- export declare function queryExistingTables(databaseUrl: string): Promise<string[]>;
330
+ /** Every CHECK and EXCLUDE constraint the database holds. @see UNDECLARABLE_CONSTRAINTS_SQL */
331
+ export declare function queryUndeclarableConstraints(databaseUrl: string): Promise<ExistingConstraint[]>;
332
+ /**
333
+ * Patterns keeping Atlas away from the CHECK and EXCLUDE constraints the
334
+ * collections do not declare — which, since a collection cannot declare
335
+ * either, is all of them. See `schema/undeclarable-constraints.ts`.
336
+ *
337
+ * Fails CLOSED, like {@link getTableExcludes}: without the catalogue nothing
338
+ * says which constraints are there, and a partial list lets the push drop a
339
+ * rule the database enforces. `desiredSql` is the `schema.sql` Atlas is about
340
+ * to diff against; a constraint it declares is Atlas's to manage.
341
+ */
342
+ export declare function getUndeclaredConstraintExcludes(databaseUrl: string, desiredSql: string, deps?: {
343
+ queryConstraints?: (databaseUrl: string) => Promise<ExistingConstraint[]>;
344
+ }): Promise<string[]>;
345
+ /** A table or view as the catalogue names it. */
346
+ export interface ExistingTable {
347
+ schema: string;
348
+ table: string;
349
+ }
350
+ export declare function queryExistingTables(databaseUrl: string): Promise<ExistingTable[]>;
283
351
  /**
284
352
  * Raised when the exclude list could not be built. `db push` MUST abort on
285
353
  * this rather than continue: the exclude list is the only thing shielding
@@ -304,21 +372,7 @@ export declare class ExcludeIntrospectionError extends Error {
304
372
  * `deps` is injectable for tests; production uses the real pg-backed queries.
305
373
  */
306
374
  export declare function getTableExcludes(databaseUrl: string, collectionsPath: string, deps?: {
307
- queryExistingTables?: (databaseUrl: string) => Promise<string[]>;
375
+ queryExistingTables?: (databaseUrl: string) => Promise<ExistingTable[]>;
308
376
  getIncludes?: (collectionsPath: string) => Promise<string[]>;
309
377
  }): Promise<string[]>;
310
- /**
311
- * Ask a yes/no question on an interactive terminal.
312
- *
313
- * The `isTTY` guard is the contract, not an optimisation: non-interactive
314
- * shells (CI, pipes, agents) can never answer, and `readline` on a
315
- * non-TTY stdin resolves with whatever the pipe happens to contain — or never
316
- * resolves at all. Returning false there is what makes an unattended
317
- * `db push` abort instead of auto-confirming a destructive change. Callers
318
- * should already have gone through {@link decidePushSafety}, which decides
319
- * whether interactive confirmation is even possible; this is the backstop.
320
- *
321
- * Lives here rather than in cli.ts so it is reachable from a test — cli.ts uses
322
- * `import.meta` and cannot be imported by the jest runner.
323
- */
324
- export declare function promptConfirm(question: string): Promise<boolean>;
378
+ export {};
@@ -1,34 +1,22 @@
1
- /**
2
- * Terminal output for the `rebase db|schema|doctor` commands.
3
- *
4
- * These commands used to write every line through `logger`, and that is a
5
- * category error with three separate consequences:
6
- *
7
- * - `logger` prefixes each line with its own level, so a box-drawn report
8
- * arrived as `ℹ️ [INFO] ┌─ ✗ Missing Column ───` and the frame no longer
9
- * lined up with anything;
10
- * - `logger` is gated by `LOG_LEVEL`, which ships in the scaffold's own
11
- * `.env.example` — a developer who quietened their dev server with
12
- * `LOG_LEVEL=warn` got a `rebase db push` that printed almost nothing and
13
- * still exited non-zero, indistinguishable from a crash;
14
- * - under `NODE_ENV=production` `logger` emits JSON, so the whole report
15
- * became log records with the chalk escape codes embedded in them.
16
- *
17
- * A CLI's report *is* its return value. It goes to the terminal unconditionally
18
- * and unadorned. `packages/cli` has always written its output this way; this is
19
- * the same three functions for the plugin CLI that `rebase` delegates to.
20
- *
21
- * `logger` still belongs in this package's *runtime* — a request handler has no
22
- * terminal and its lines want levels, timestamps and redaction. The rule is the
23
- * caller, not the severity: anything a developer reads because they typed a
24
- * command goes here, anything a server emits while running goes to `logger`.
25
- *
26
- * Errors and warnings go to stderr so `rebase db push > plan.txt` keeps the
27
- * diagnosis on the terminal where it is readable.
28
- */
29
1
  /** One line of human-facing output on stdout. */
30
2
  export declare const out: (line?: string) => void;
31
3
  /** One line of human-facing warning output on stderr. */
32
4
  export declare const outWarn: (line?: string) => void;
33
5
  /** One line of human-facing error output on stderr. */
34
6
  export declare const outError: (line?: string) => void;
7
+ /**
8
+ * Whether a failure should be printed with its stack — `rebase --debug`, which
9
+ * the launcher passes down as `REBASE_DEBUG`, or `REBASE_DEBUG` set by hand.
10
+ */
11
+ export declare const wantsStack: () => boolean;
12
+ /**
13
+ * An error as a person reads it: its message, and its stack only under
14
+ * `--debug`.
15
+ *
16
+ * The rule `rebase` itself follows (`bin/rebase.js`). These commands run in a
17
+ * child process the launcher's handler never sees, so a syntax error in a
18
+ * collection file reached the terminal as `Doctor failed CollectionConfigError:`
19
+ * followed by twenty frames of loader internals, under a sentence that already
20
+ * said which file and which line.
21
+ */
22
+ export declare const describeFailure: (error: unknown) => string;
@@ -1,6 +1,7 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  __createRequire(import.meta.url);
3
- import { n as __commonJSMin } from "./__vite-browser-external-BnuHet1e.js";
3
+ import { t as __commonJSMin } from "./rolldown-runtime-V7rFbMRe.js";
4
+ import readline from "readline";
4
5
  //#region ../../node_modules/.pnpm/arg@5.0.2/node_modules/arg/index.js
5
6
  var require_arg = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6
7
  var flagSymbol = Symbol("arg flag");
@@ -82,6 +83,51 @@ var require_arg = /* @__PURE__ */ __commonJSMin(((exports, module) => {
82
83
  module.exports = arg;
83
84
  }));
84
85
  //#endregion
85
- export { require_arg as t };
86
+ //#region src/cli-prompt.ts
87
+ /**
88
+ * The one yes/no question the driver CLI asks: before a destructive `db push`,
89
+ * before a `db restore` without `--yes`, before `db branch prune` removes
90
+ * anything, and before `schema introspect` samples rows.
91
+ */
92
+ /**
93
+ * Ask a yes/no question on an interactive terminal; `true` only for "y" or
94
+ * "yes".
95
+ *
96
+ * The `isTTY` guard is the contract, not an optimisation: non-interactive
97
+ * shells (CI, pipes, agents) can never answer, and `readline` on a non-TTY
98
+ * stdin resolves with whatever the pipe happens to contain, or never resolves
99
+ * at all. Returning false there is what makes an unattended `db push` abort
100
+ * instead of auto-confirming a destructive change. Callers decide first
101
+ * whether interactive confirmation is possible (`decidePushSafety` for a
102
+ * push); this is the backstop.
103
+ *
104
+ * Ctrl-C and Ctrl-D answer no. On a terminal readline reads Ctrl-C as a key,
105
+ * not as a signal, and with nothing listening it only pauses the input: the
106
+ * question never resolves, and the open database connections behind it keep
107
+ * the process alive, so the command hung instead of stopping. Answering no
108
+ * sends it down the path that says "Aborted" and cleans up.
109
+ */
110
+ async function promptConfirm(question) {
111
+ if (!process.stdin.isTTY) return false;
112
+ const rl = readline.createInterface({
113
+ input: process.stdin,
114
+ output: process.stdout
115
+ });
116
+ try {
117
+ const answer = await new Promise((resolve) => {
118
+ rl.once("SIGINT", () => {
119
+ process.stdout.write("\n");
120
+ resolve("");
121
+ });
122
+ rl.once("close", () => resolve(""));
123
+ rl.question(question, resolve);
124
+ });
125
+ return /^y(es)?$/i.test(answer.trim());
126
+ } finally {
127
+ rl.close();
128
+ }
129
+ }
130
+ //#endregion
131
+ export { require_arg as n, promptConfirm as t };
86
132
 
87
- //# sourceMappingURL=arg-Dni7MzLB.js.map
133
+ //# sourceMappingURL=cli-prompt-egtNKkZl.js.map