@rebasepro/server-postgres 0.17.3 → 0.18.1

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 (204) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +31 -0
  3. package/dist/BranchService-ByLfM_Tt.js +360 -0
  4. package/dist/BranchService-ByLfM_Tt.js.map +1 -0
  5. package/dist/__vite-browser-external-BnuHet1e.js +46 -0
  6. package/dist/__vite-browser-external-BnuHet1e.js.map +1 -0
  7. package/dist/arg-Dni7MzLB.js +87 -0
  8. package/dist/arg-Dni7MzLB.js.map +1 -0
  9. package/dist/auth-users-columns-D2LBFrMH.js +116 -0
  10. package/dist/auth-users-columns-D2LBFrMH.js.map +1 -0
  11. package/dist/backup-argv.d.ts +19 -0
  12. package/dist/backup-cli-oM9WQVlV.js +408 -0
  13. package/dist/backup-cli-oM9WQVlV.js.map +1 -0
  14. package/dist/backup-service-Br3tqwsy.js +715 -0
  15. package/dist/backup-service-Br3tqwsy.js.map +1 -0
  16. package/dist/branch-argv.d.ts +28 -0
  17. package/dist/branch-prune.d.ts +77 -0
  18. package/dist/cli-collections-path.d.ts +31 -0
  19. package/dist/cli-errors-DxN4yzdH.js +657 -0
  20. package/dist/cli-errors-DxN4yzdH.js.map +1 -0
  21. package/dist/cli-errors.d.ts +123 -0
  22. package/dist/cli-flags.d.ts +101 -0
  23. package/dist/cli-helpers.d.ts +94 -10
  24. package/dist/cli-output-CNdMql-L.js +47 -0
  25. package/dist/cli-output-CNdMql-L.js.map +1 -0
  26. package/dist/cli.js +2020 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/collection-index-BHgT_TKd.js +276 -0
  29. package/dist/collection-index-BHgT_TKd.js.map +1 -0
  30. package/dist/{collections-schema-version-BMeu3cgv.js → collections-schema-version-T6cGvrDi.js} +1 -2
  31. package/dist/{collections-schema-version-BMeu3cgv.js.map → collections-schema-version-T6cGvrDi.js.map} +1 -1
  32. package/dist/{connection-GOKU3Hu5.js → databasePoolManager-Bj5FbeAs.js} +112 -40
  33. package/dist/databasePoolManager-Bj5FbeAs.js.map +1 -0
  34. package/dist/databasePoolManager.d.ts +27 -0
  35. package/dist/doctor-D7HWmGzs.js +974 -0
  36. package/dist/doctor-D7HWmGzs.js.map +1 -0
  37. package/dist/{ensure-collection-policies-UCqgv_8c.js → ensure-collection-policies-2c2NV8zX.js} +7 -27
  38. package/dist/ensure-collection-policies-2c2NV8zX.js.map +1 -0
  39. package/dist/ensure-collection-tables-D4wJzM4y.js +820 -0
  40. package/dist/ensure-collection-tables-D4wJzM4y.js.map +1 -0
  41. package/dist/ensure-tables-CIojK-Rx.js +650 -0
  42. package/dist/ensure-tables-CIojK-Rx.js.map +1 -0
  43. package/dist/generate-drizzle-schema-CwEgVyjO.js +123 -0
  44. package/dist/generate-drizzle-schema-CwEgVyjO.js.map +1 -0
  45. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js +528 -0
  46. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js.map +1 -0
  47. package/dist/{ensure-collection-tables-DgVixhX3.js → generate-postgres-ddl-logic-CtnpIBVv.js} +126 -984
  48. package/dist/generate-postgres-ddl-logic-CtnpIBVv.js.map +1 -0
  49. package/dist/generated-schema-staleness-DQdfJl2A.js +157 -0
  50. package/dist/generated-schema-staleness-DQdfJl2A.js.map +1 -0
  51. package/dist/index.d.ts +12 -0
  52. package/dist/index.es.js +7423 -1133
  53. package/dist/index.es.js.map +1 -1
  54. package/dist/introspect-db-logic-C6LQdTxj.js +1378 -0
  55. package/dist/introspect-db-logic-C6LQdTxj.js.map +1 -0
  56. package/dist/policy-drift-kNJ6X2Uj.js +313 -0
  57. package/dist/policy-drift-kNJ6X2Uj.js.map +1 -0
  58. package/dist/{backup-service-DCk7KhhL.js → rls-bootstrap-sql-DLDnUjtx.js} +737 -2689
  59. package/dist/rls-bootstrap-sql-DLDnUjtx.js.map +1 -0
  60. package/dist/{rls-enforcement-DvAbL9YJ.js → rls-enforcement-DeYEjYLt.js} +65 -190
  61. package/dist/rls-enforcement-DeYEjYLt.js.map +1 -0
  62. package/dist/schema/bin/generate-drizzle-schema.d.ts +1 -0
  63. package/dist/schema/bin/generate-postgres-ddl.d.ts +1 -0
  64. package/dist/schema/column-type-drift.d.ts +79 -0
  65. package/dist/schema/doctor-cli.js +129 -0
  66. package/dist/schema/doctor-cli.js.map +1 -0
  67. package/dist/schema/doctor.d.ts +42 -0
  68. package/dist/schema/ensure-collection-tables.d.ts +90 -0
  69. package/dist/schema/generate-drizzle-schema.d.ts +1 -1
  70. package/dist/schema/generate-drizzle-schema.js +24 -0
  71. package/dist/schema/generate-drizzle-schema.js.map +1 -0
  72. package/dist/schema/generate-next-step.d.ts +30 -0
  73. package/dist/schema/generate-postgres-ddl-logic.d.ts +28 -0
  74. package/dist/schema/generate-postgres-ddl.d.ts +1 -1
  75. package/dist/schema/generate-postgres-ddl.js +138 -0
  76. package/dist/schema/generate-postgres-ddl.js.map +1 -0
  77. package/dist/schema/generated-schema-staleness.d.ts +37 -0
  78. package/dist/schema/introspect-db-queries.d.ts +34 -0
  79. package/dist/schema/introspect-db.js +866 -0
  80. package/dist/schema/introspect-db.js.map +1 -0
  81. package/dist/security/rls-enforcement.d.ts +63 -2
  82. package/dist/services/BranchService.d.ts +86 -1
  83. package/dist/services/collection-helpers.d.ts +1 -1
  84. package/dist/services/realtimeService.d.ts +30 -2
  85. package/dist/services/row-pipeline.d.ts +12 -1
  86. package/dist/source-Br7L7GOI.js +410 -0
  87. package/dist/source-Br7L7GOI.js.map +1 -0
  88. package/dist/utils/pg-error-utils.d.ts +3 -1
  89. package/dist/utils/pg-numeric-number-patch.d.ts +31 -0
  90. package/dist/vector-index-DkWxm2de.js +309 -0
  91. package/dist/vector-index-DkWxm2de.js.map +1 -0
  92. package/package.json +32 -27
  93. package/dist/backup-service-DCk7KhhL.js.map +0 -1
  94. package/dist/collection-index-BRUg10H5.js +0 -5690
  95. package/dist/collection-index-BRUg10H5.js.map +0 -1
  96. package/dist/connection-GOKU3Hu5.js.map +0 -1
  97. package/dist/ensure-collection-policies-UCqgv_8c.js.map +0 -1
  98. package/dist/ensure-collection-tables-DgVixhX3.js.map +0 -1
  99. package/dist/rls-bootstrap-sql-B5C9LoJ6.js +0 -244
  100. package/dist/rls-bootstrap-sql-B5C9LoJ6.js.map +0 -1
  101. package/dist/rls-enforcement-DvAbL9YJ.js.map +0 -1
  102. package/dist/src-DiB5RP2Z.js +0 -541
  103. package/dist/src-DiB5RP2Z.js.map +0 -1
  104. package/dist/websocket-BZ4H5wUz.js +0 -8198
  105. package/dist/websocket-BZ4H5wUz.js.map +0 -1
  106. package/src/PostgresAdapter.ts +0 -91
  107. package/src/PostgresBackendDriver.ts +0 -1857
  108. package/src/PostgresBootstrapper.ts +0 -1157
  109. package/src/auth/ensure-tables.ts +0 -896
  110. package/src/auth/schema-version.ts +0 -260
  111. package/src/auth/services.ts +0 -1610
  112. package/src/backup/backup-cli.ts +0 -520
  113. package/src/backup/backup-cron.ts +0 -212
  114. package/src/backup/backup-logic.ts +0 -93
  115. package/src/backup/backup-service.ts +0 -485
  116. package/src/backup/index.ts +0 -12
  117. package/src/backup/pg-tools.ts +0 -403
  118. package/src/backup/retention.ts +0 -86
  119. package/src/cli-errors.ts +0 -265
  120. package/src/cli-helpers.ts +0 -569
  121. package/src/cli-output.ts +0 -43
  122. package/src/cli.ts +0 -1339
  123. package/src/collections/PostgresCollectionRegistry.ts +0 -108
  124. package/src/collections/buildRegistry.ts +0 -68
  125. package/src/collections/validate-relations.ts +0 -402
  126. package/src/connection.ts +0 -333
  127. package/src/data-transformer.ts +0 -845
  128. package/src/databasePoolManager.ts +0 -95
  129. package/src/history/HistoryService.ts +0 -254
  130. package/src/history/ensure-history-table.ts +0 -53
  131. package/src/index.ts +0 -19
  132. package/src/interfaces.ts +0 -60
  133. package/src/module-dir.ts +0 -7
  134. package/src/schema/atlas-argv.ts +0 -94
  135. package/src/schema/auth-schema.ts +0 -298
  136. package/src/schema/auth-users-columns.ts +0 -131
  137. package/src/schema/carved-out-migration.ts +0 -404
  138. package/src/schema/classify-change.ts +0 -436
  139. package/src/schema/collection-index.ts +0 -427
  140. package/src/schema/collections-schema-version.ts +0 -103
  141. package/src/schema/destructive-sql.ts +0 -94
  142. package/src/schema/doctor-cli.ts +0 -66
  143. package/src/schema/doctor-policy-checks.ts +0 -105
  144. package/src/schema/doctor.ts +0 -837
  145. package/src/schema/drizzle-ddl.ts +0 -33
  146. package/src/schema/dynamic-tables.test.ts +0 -302
  147. package/src/schema/dynamic-tables.ts +0 -293
  148. package/src/schema/ensure-collection-policies.ts +0 -198
  149. package/src/schema/ensure-collection-tables.test.ts +0 -518
  150. package/src/schema/ensure-collection-tables.ts +0 -1267
  151. package/src/schema/generate-drizzle-schema-logic.ts +0 -957
  152. package/src/schema/generate-drizzle-schema.ts +0 -143
  153. package/src/schema/generate-postgres-ddl-logic.ts +0 -1339
  154. package/src/schema/generate-postgres-ddl.ts +0 -180
  155. package/src/schema/generate-schema-commit.ts +0 -267
  156. package/src/schema/generated-schema-staleness.ts +0 -284
  157. package/src/schema/introspect-db-constraints.ts +0 -385
  158. package/src/schema/introspect-db-inference.ts +0 -255
  159. package/src/schema/introspect-db-logic.ts +0 -1387
  160. package/src/schema/introspect-db-naming.ts +0 -15
  161. package/src/schema/introspect-db-project.ts +0 -78
  162. package/src/schema/introspect-db-queries.ts +0 -326
  163. package/src/schema/introspect-db-structure.ts +0 -670
  164. package/src/schema/introspect-db-types.ts +0 -56
  165. package/src/schema/introspect-db.ts +0 -257
  166. package/src/schema/introspect-runtime.test.ts +0 -260
  167. package/src/schema/introspect-runtime.ts +0 -327
  168. package/src/schema/non-sql-collections.test.ts +0 -131
  169. package/src/schema/rls-bootstrap-sql.ts +0 -288
  170. package/src/schema/search-column.ts +0 -643
  171. package/src/schema/test-schema.ts +0 -11
  172. package/src/schema/vector-index.ts +0 -491
  173. package/src/security/anonymous-grants.test.ts +0 -73
  174. package/src/security/policy-drift.test.ts +0 -435
  175. package/src/security/policy-drift.ts +0 -473
  176. package/src/security/rls-enforcement.ts +0 -505
  177. package/src/services/BranchService.ts +0 -326
  178. package/src/services/FetchService.ts +0 -2115
  179. package/src/services/PersistService.ts +0 -557
  180. package/src/services/RelationService.ts +0 -978
  181. package/src/services/RelationWriteService.ts +0 -653
  182. package/src/services/cdc/CdcListener.ts +0 -103
  183. package/src/services/cdc/junction-tables.ts +0 -91
  184. package/src/services/cdc/trigger-cdc.ts +0 -173
  185. package/src/services/channel-bus/ChannelBus.ts +0 -44
  186. package/src/services/channel-bus/PostgresChannelBus.ts +0 -299
  187. package/src/services/channel-bus/index.ts +0 -114
  188. package/src/services/channel-history.ts +0 -424
  189. package/src/services/channel-presence.ts +0 -185
  190. package/src/services/collection-helpers.ts +0 -420
  191. package/src/services/dataService.ts +0 -256
  192. package/src/services/index.ts +0 -14
  193. package/src/services/junction-writes.ts +0 -295
  194. package/src/services/nested-path.ts +0 -145
  195. package/src/services/pg-notify-listener.ts +0 -151
  196. package/src/services/realtimeService.ts +0 -2545
  197. package/src/services/row-pipeline.ts +0 -240
  198. package/src/services/write-denial.ts +0 -55
  199. package/src/types.ts +0 -4
  200. package/src/utils/connection-string.ts +0 -58
  201. package/src/utils/drizzle-conditions.ts +0 -2743
  202. package/src/utils/pg-array-null-patch.ts +0 -42
  203. package/src/utils/pg-error-utils.ts +0 -391
  204. package/src/websocket.ts +0 -855
@@ -1,12 +1,12 @@
1
1
  import { createRequire as __createRequire } from "module";
2
- import process from "process";
3
2
  __createRequire(import.meta.url);
4
- import { d as __require, f as __toESM, l as __commonJSMin, u as __exportAll } from "./connection-GOKU3Hu5.js";
5
- import "./collection-index-BRUg10H5.js";
6
- import "./src-DiB5RP2Z.js";
3
+ import { a as __toESM, i as __require, n as __commonJSMin, r as __exportAll, t as require___vite_browser_external } from "./__vite-browser-external-BnuHet1e.js";
4
+ import { o as isRebaseIndexName } from "./collection-index-BHgT_TKd.js";
5
+ import { r as outWarn, t as out } from "./cli-output-CNdMql-L.js";
6
+ import { t as chalk } from "./source-Br7L7GOI.js";
7
+ import { LEGACY_RLS_SCHEMA, REBASE_SCHEMA, isManyToMany } from "@rebasepro/types";
7
8
  import fs from "fs";
8
9
  import path from "path";
9
- import os from "os";
10
10
  import { fileURLToPath } from "node:url";
11
11
  import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
12
12
  import { StringDecoder } from "node:string_decoder";
@@ -23,8 +23,8 @@ import { appendFileSync, createReadStream, createWriteStream, readFileSync, stat
23
23
  import { finished } from "node:stream/promises";
24
24
  import { Duplex, PassThrough, Readable, Transform, Writable, getDefaultHighWaterMark } from "node:stream";
25
25
  import { Buffer as Buffer$1 } from "node:buffer";
26
- import "module";
27
- import { fileURLToPath as fileURLToPath$1 } from "url";
26
+ import { createRequire } from "module";
27
+ import { fileURLToPath as fileURLToPath$1, pathToFileURL } from "url";
28
28
  //#region src/utils/connection-string.ts
29
29
  /**
30
30
  * Connection-string rewrites for the tools Rebase shells out to.
@@ -80,321 +80,6 @@ function forLibpq(connectionString) {
80
80
  return url.toString();
81
81
  }
82
82
  //#endregion
83
- //#region src/backup/pg-tools.ts
84
- /**
85
- * Pure helpers for the backup/restore commands.
86
- *
87
- * Everything in this file is side-effect free so it can be unit-tested
88
- * without a live Postgres server, matching the constraint that CI must
89
- * not require a database.
90
- */
91
- /**
92
- * Extract the database name from a Postgres connection string.
93
- * Returns `null` when the URL has no database path (e.g. bare host).
94
- */
95
- function parseDbNameFromUrl(connectionString) {
96
- try {
97
- const name = new URL(connectionString).pathname.replace(/^\//, "").trim();
98
- return name.length > 0 ? name : null;
99
- } catch {
100
- const match = connectionString.match(/\/([^/?]+)(\?|$)/);
101
- return match && match[1] ? match[1] : null;
102
- }
103
- }
104
- /**
105
- * Swap the database name in a connection string, preserving credentials,
106
- * host, port and query params. Used by `--target-db` / `--create-db` so a
107
- * restore can target a fresh database instead of clobbering the live one.
108
- */
109
- function withDatabaseName(connectionString, dbName) {
110
- try {
111
- const parsed = new URL(connectionString);
112
- parsed.pathname = `/${dbName}`;
113
- return parsed.toString();
114
- } catch {
115
- return connectionString.replace(/\/([^/?]+)(\?|$)/, `/${dbName}$2`);
116
- }
117
- }
118
- /**
119
- * Parse the major version out of `pg_dump --version` / `pg_restore --version`
120
- * output, e.g. `"pg_dump (PostgreSQL) 16.2"` → `16`. Handles the pre-10
121
- * `9.6.x` scheme (returns `9`) and beta strings like `"17beta1"`.
122
- */
123
- function parsePgToolMajor(versionOutput) {
124
- const match = versionOutput.match(/(\d+)(?:\.(\d+))?/);
125
- if (!match) return null;
126
- const major = Number(match[1]);
127
- if (!Number.isFinite(major)) return null;
128
- if (major === 9 && match[2] !== void 0) return 9;
129
- return major;
130
- }
131
- /**
132
- * Convert `SELECT current_setting('server_version_num')` (e.g. `160002`)
133
- * into a major version (`16`). Also accepts pre-10 encodings like `90603`
134
- * → `9`.
135
- */
136
- function serverVersionNumToMajor(versionNum) {
137
- const num = typeof versionNum === "string" ? Number(versionNum) : versionNum;
138
- if (!Number.isFinite(num) || num <= 0) return null;
139
- if (num < 1e5) return Math.floor(num / 1e4);
140
- return Math.floor(num / 1e4);
141
- }
142
- /**
143
- * pg_dump / pg_restore must be **at least** as new as the server they talk
144
- * to. A newer client against an older server is supported; an older client
145
- * against a newer server is not and produces corrupt or rejected output.
146
- */
147
- function checkToolServerCompatibility(toolMajor, serverMajor) {
148
- if (toolMajor === null) return {
149
- compatible: false,
150
- reason: "Could not determine the client tool version."
151
- };
152
- if (serverMajor === null) return {
153
- compatible: false,
154
- reason: "Could not determine the Postgres server version."
155
- };
156
- if (toolMajor < serverMajor) return {
157
- compatible: false,
158
- reason: `Client tool is Postgres ${toolMajor} but the server is Postgres ${serverMajor}. pg_dump/pg_restore must be the same major version as the server or newer. Install Postgres ${serverMajor} client tools.`
159
- };
160
- return { compatible: true };
161
- }
162
- /**
163
- * Build a deterministic, sortable backup file name:
164
- * `rebase-<db>-<YYYYMMDD>T<HHMMSS>Z.dump`
165
- *
166
- * The UTC timestamp is embedded so retention pruning can recover the
167
- * creation time from the object key alone, without extra metadata.
168
- */
169
- function buildBackupFilename(dbName, date = /* @__PURE__ */ new Date()) {
170
- const stamp = date.toISOString().replace(/\.\d+Z$/, "Z").replace(/[-:]/g, "");
171
- return `rebase-${dbName.replace(/[^a-zA-Z0-9_-]/g, "_")}-${stamp}.dump`;
172
- }
173
- /**
174
- * Recover the creation timestamp encoded in a backup file name by
175
- * {@link buildBackupFilename}. Returns `null` for names that don't match,
176
- * so foreign objects in a shared prefix are never pruned.
177
- */
178
- function parseBackupTimestamp(fileName) {
179
- const match = (fileName.split("/").pop() ?? fileName).match(/-(\d{8})T(\d{6})Z\.dump$/);
180
- if (!match) return null;
181
- const [, ymd, hms] = match;
182
- const iso = `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}T${hms.slice(0, 2)}:${hms.slice(2, 4)}:${hms.slice(4, 6)}Z`;
183
- const date = new Date(iso);
184
- return Number.isNaN(date.getTime()) ? null : date;
185
- }
186
- /**
187
- * Parse a destination string into a structured {@link BackupDestination}.
188
- * `s3://bucket/prefix` and `gs://bucket/prefix` map to object storage;
189
- * anything else is treated as a local path.
190
- */
191
- function parseBackupDestination(out) {
192
- const s3 = out.match(/^s3:\/\/([^/]+)\/?(.*)$/);
193
- if (s3) return {
194
- kind: "s3",
195
- bucket: s3[1],
196
- prefix: stripTrailingSlash(s3[2])
197
- };
198
- const gcs = out.match(/^gs:\/\/([^/]+)\/?(.*)$/);
199
- if (gcs) return {
200
- kind: "gcs",
201
- bucket: gcs[1],
202
- prefix: stripTrailingSlash(gcs[2])
203
- };
204
- return {
205
- kind: "local",
206
- path: out
207
- };
208
- }
209
- function stripTrailingSlash(s) {
210
- return s.replace(/\/+$/, "");
211
- }
212
- /**
213
- * Join a storage prefix and a file name without producing a leading or
214
- * doubled slash.
215
- */
216
- function joinStorageKey(prefix, fileName) {
217
- const clean = prefix.replace(/^\/+|\/+$/g, "");
218
- return clean.length > 0 ? `${clean}/${fileName}` : fileName;
219
- }
220
- /**
221
- * `PGOPTIONS` carrying an identity, for a libpq tool that has no other way to
222
- * set a GUC.
223
- *
224
- * A backslash escape rather than quoting, which is what libpq's `-c` parsing
225
- * takes: a space inside a value ends the option otherwise, so a role list is
226
- * comma-joined and never spaced.
227
- */
228
- function buildRowSecurityPgOptions(identity) {
229
- const escape = (value) => value.replace(/([\\ ])/g, "\\$1");
230
- return [
231
- `-c app.uid=${escape(identity.uid)}`,
232
- `-c app.user_id=${escape(identity.uid)}`,
233
- `-c app.user_roles=${escape(identity.roles.join(","))}`
234
- ].join(" ");
235
- }
236
- /**
237
- * Assemble the `pg_dump` argument vector. Uses the custom format (`-Fc`),
238
- * which is compressed and restorable selectively via `pg_restore`.
239
- */
240
- function buildPgDumpArgs(opts) {
241
- const args = [
242
- "--format=custom",
243
- "--no-password",
244
- `--file=${opts.outFile}`
245
- ];
246
- if (opts.noOwner) args.push("--no-owner");
247
- if (opts.rowSecurity) args.push("--enable-row-security");
248
- for (const schema of opts.excludeSchemas ?? []) args.push(`--exclude-schema=${schema}`);
249
- args.push(forLibpq(opts.connectionString));
250
- return args;
251
- }
252
- /**
253
- * Whether a `pg_dump` failure is the row-security one, and what to do about it.
254
- *
255
- * The error text names the table and nothing else, so the first read of it is
256
- * "why would a backup be affected by RLS at all?" — the answer being that the
257
- * dumping role is not the tables' owner and has no `BYPASSRLS`, which is the
258
- * normal state of the `postgres` user on Cloud SQL, RDS and every other managed
259
- * Postgres. Nothing about that is visible from the message.
260
- *
261
- * Returns `null` for any other failure, so the caller reports it unchanged.
262
- */
263
- function diagnoseRowSecurityDumpFailure(error) {
264
- const text = [error?.stderr, error?.message].map((part) => typeof part === "string" ? part : "").join("\n");
265
- if (!/row-level security policy/i.test(text)) return null;
266
- const table = text.match(/for table "([^"]+)"/)?.[1];
267
- return [
268
- `pg_dump cannot read ${table ? `"${table}"` : "one of the tables"} because row-level security applies to it.`,
269
- "",
270
- " The dumping role is neither the table's owner nor `BYPASSRLS`, which is the normal",
271
- " state of the `postgres` user on Cloud SQL, RDS and other managed Postgres — there is",
272
- " no superuser to hand out.",
273
- "",
274
- " Two ways out:",
275
- "",
276
- " • Grant the dumping role BYPASSRLS, or make it the owner, and run this again. The",
277
- " dump then contains every row, which is what a backup should mean.",
278
- "",
279
- " • Re-run with --enable-row-security to dump as an admin subject instead. Rebase",
280
- " sets `app.uid`/`app.user_roles` so the generated `admin_full_access` policy",
281
- " admits the dump. Read the warning it prints: the result contains exactly the",
282
- " rows those policies admit, and any table whose policies do not include an",
283
- " admin rule comes out short — with no error.",
284
- "",
285
- " Do not reach for a bare `pg_dump --enable-row-security` by hand. Without the",
286
- " settings above it succeeds and silently omits rows."
287
- ].join("\n");
288
- }
289
- /**
290
- * Assemble the `pg_restore` argument vector for a custom-format dump.
291
- */
292
- function buildPgRestoreArgs(opts) {
293
- const args = [
294
- "--format=custom",
295
- "--no-password",
296
- `--dbname=${forLibpq(opts.connectionString)}`
297
- ];
298
- if (opts.clean) args.push("--clean", "--if-exists");
299
- if (opts.noOwner) args.push("--no-owner");
300
- if (opts.exitOnError !== false) args.push("--exit-on-error");
301
- args.push(opts.inputFile);
302
- return args;
303
- }
304
- /**
305
- * Assemble the `pg_restore --list` argument vector. Reading a dump's table
306
- * of contents parses the whole archive without touching a database, so it is
307
- * a cheap integrity check that the file isn't truncated or corrupt.
308
- */
309
- function buildPgRestoreListArgs(inputFile) {
310
- return ["--list", inputFile];
311
- }
312
- /**
313
- * Assemble the `pg_dumpall --globals-only` argument vector. Roles (and other
314
- * cluster-wide objects) live outside any single database, so a per-database
315
- * `pg_dump` omits them. Without the `rebase_user` role the RLS GRANT
316
- * statements in the main dump fail on restore and RLS is silently lost — so
317
- * every backup captures the globals into a sidecar `.globals.sql`.
318
- *
319
- * `--no-role-passwords` keeps role secrets out of the artifact (backups may
320
- * be shipped off-box); roles are recreated password-less and re-secured by
321
- * the operator.
322
- */
323
- function buildPgDumpallGlobalsArgs(opts) {
324
- return [
325
- "--globals-only",
326
- "--no-role-passwords",
327
- "--no-password",
328
- `--file=${opts.outFile}`,
329
- `--dbname=${forLibpq(opts.connectionString)}`
330
- ];
331
- }
332
- /**
333
- * Derive the globals sidecar path/key for a given `.dump` file. Keeps the
334
- * two artifacts adjacent so listing, uploading and pruning can find one from
335
- * the other. A name that doesn't end in `.dump` is returned unchanged with a
336
- * `.globals.sql` suffix appended.
337
- */
338
- function globalsFileForDump(dumpPath) {
339
- return dumpPath.endsWith(".dump") ? dumpPath.slice(0, -5) + ".globals.sql" : dumpPath + ".globals.sql";
340
- }
341
- /**
342
- * Split a `pg_dumpall --globals-only` script into individual statements.
343
- * Used when replaying globals on restore so each `CREATE ROLE` / `GRANT`
344
- * can run independently and a benign "role already exists" on one doesn't
345
- * abort the rest. Drops `--` comment lines and blank statements.
346
- */
347
- function splitGlobalsStatements(sql) {
348
- return sql.split("\n").filter((line) => {
349
- const trimmed = line.trim();
350
- return !trimmed.startsWith("--") && !trimmed.startsWith("\\");
351
- }).join("\n").split(";").map((s) => s.trim()).filter((s) => s.length > 0);
352
- }
353
- /**
354
- * Resolve the Postgres connection string the backup commands should use,
355
- * mirroring the precedence the branch command already relies on.
356
- */
357
- function resolveConnectionString(env) {
358
- return env.DATABASE_URL || env.ADMIN_CONNECTION_STRING || null;
359
- }
360
- //#endregion
361
- //#region src/backup/retention.ts
362
- /**
363
- * Retention pruning for scheduled backups. Pure logic — no I/O — so it can
364
- * be exhaustively unit-tested without touching a storage backend.
365
- */
366
- /**
367
- * Decide which backups to delete under the given retention policy.
368
- *
369
- * Rules, applied in order:
370
- * 1. Objects whose key isn't a recognised rebase backup (no parseable
371
- * timestamp and no `createdAt`) are never selected — foreign files in a
372
- * shared bucket are left untouched.
373
- * 2. The `keepMinimum` newest backups are always retained.
374
- * 3. Of the remainder, any older than `retentionDays` are selected for
375
- * deletion.
376
- *
377
- * Returns the keys to delete, oldest first.
378
- */
379
- function selectBackupsToPrune(backups, options) {
380
- const retentionDays = options.retentionDays ?? 0;
381
- const keepMinimum = Math.max(0, options.keepMinimum ?? 0);
382
- const now = options.now ?? /* @__PURE__ */ new Date();
383
- if (retentionDays <= 0) return [];
384
- const dated = backups.map((b) => {
385
- const createdAt = b.createdAt ?? parseBackupTimestamp(b.key);
386
- return createdAt ? {
387
- key: b.key,
388
- createdAt
389
- } : null;
390
- }).filter((b) => b !== null);
391
- dated.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
392
- const cutoff = now.getTime() - retentionDays * 24 * 60 * 60 * 1e3;
393
- const toDelete = dated.slice(keepMinimum).filter((b) => b.createdAt.getTime() < cutoff);
394
- toDelete.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
395
- return toDelete.map((b) => b.key);
396
- }
397
- //#endregion
398
83
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
399
84
  function isPlainObject(value) {
400
85
  if (typeof value !== "object" || value === null) return false;
@@ -6566,2065 +6251,149 @@ createExeca(mapNode);
6566
6251
  createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
6567
6252
  var { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
6568
6253
  //#endregion
6569
- //#region __vite-browser-external
6570
- var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6571
- module.exports = {};
6572
- }));
6573
- //#endregion
6574
- //#region ../../node_modules/.pnpm/color-name@1.1.4/node_modules/color-name/index.js
6575
- var require_color_name = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6576
- module.exports = {
6577
- "aliceblue": [
6578
- 240,
6579
- 248,
6580
- 255
6581
- ],
6582
- "antiquewhite": [
6583
- 250,
6584
- 235,
6585
- 215
6586
- ],
6587
- "aqua": [
6588
- 0,
6589
- 255,
6590
- 255
6591
- ],
6592
- "aquamarine": [
6593
- 127,
6594
- 255,
6595
- 212
6596
- ],
6597
- "azure": [
6598
- 240,
6599
- 255,
6600
- 255
6601
- ],
6602
- "beige": [
6603
- 245,
6604
- 245,
6605
- 220
6606
- ],
6607
- "bisque": [
6608
- 255,
6609
- 228,
6610
- 196
6611
- ],
6612
- "black": [
6613
- 0,
6614
- 0,
6615
- 0
6616
- ],
6617
- "blanchedalmond": [
6618
- 255,
6619
- 235,
6620
- 205
6621
- ],
6622
- "blue": [
6623
- 0,
6624
- 0,
6625
- 255
6626
- ],
6627
- "blueviolet": [
6628
- 138,
6629
- 43,
6630
- 226
6631
- ],
6632
- "brown": [
6633
- 165,
6634
- 42,
6635
- 42
6636
- ],
6637
- "burlywood": [
6638
- 222,
6639
- 184,
6640
- 135
6641
- ],
6642
- "cadetblue": [
6643
- 95,
6644
- 158,
6645
- 160
6646
- ],
6647
- "chartreuse": [
6648
- 127,
6649
- 255,
6650
- 0
6651
- ],
6652
- "chocolate": [
6653
- 210,
6654
- 105,
6655
- 30
6656
- ],
6657
- "coral": [
6658
- 255,
6659
- 127,
6660
- 80
6661
- ],
6662
- "cornflowerblue": [
6663
- 100,
6664
- 149,
6665
- 237
6666
- ],
6667
- "cornsilk": [
6668
- 255,
6669
- 248,
6670
- 220
6671
- ],
6672
- "crimson": [
6673
- 220,
6674
- 20,
6675
- 60
6676
- ],
6677
- "cyan": [
6678
- 0,
6679
- 255,
6680
- 255
6681
- ],
6682
- "darkblue": [
6683
- 0,
6684
- 0,
6685
- 139
6686
- ],
6687
- "darkcyan": [
6688
- 0,
6689
- 139,
6690
- 139
6691
- ],
6692
- "darkgoldenrod": [
6693
- 184,
6694
- 134,
6695
- 11
6696
- ],
6697
- "darkgray": [
6698
- 169,
6699
- 169,
6700
- 169
6701
- ],
6702
- "darkgreen": [
6703
- 0,
6704
- 100,
6705
- 0
6706
- ],
6707
- "darkgrey": [
6708
- 169,
6709
- 169,
6710
- 169
6711
- ],
6712
- "darkkhaki": [
6713
- 189,
6714
- 183,
6715
- 107
6716
- ],
6717
- "darkmagenta": [
6718
- 139,
6719
- 0,
6720
- 139
6721
- ],
6722
- "darkolivegreen": [
6723
- 85,
6724
- 107,
6725
- 47
6726
- ],
6727
- "darkorange": [
6728
- 255,
6729
- 140,
6730
- 0
6731
- ],
6732
- "darkorchid": [
6733
- 153,
6734
- 50,
6735
- 204
6736
- ],
6737
- "darkred": [
6738
- 139,
6739
- 0,
6740
- 0
6741
- ],
6742
- "darksalmon": [
6743
- 233,
6744
- 150,
6745
- 122
6746
- ],
6747
- "darkseagreen": [
6748
- 143,
6749
- 188,
6750
- 143
6751
- ],
6752
- "darkslateblue": [
6753
- 72,
6754
- 61,
6755
- 139
6756
- ],
6757
- "darkslategray": [
6758
- 47,
6759
- 79,
6760
- 79
6761
- ],
6762
- "darkslategrey": [
6763
- 47,
6764
- 79,
6765
- 79
6766
- ],
6767
- "darkturquoise": [
6768
- 0,
6769
- 206,
6770
- 209
6771
- ],
6772
- "darkviolet": [
6773
- 148,
6774
- 0,
6775
- 211
6776
- ],
6777
- "deeppink": [
6778
- 255,
6779
- 20,
6780
- 147
6781
- ],
6782
- "deepskyblue": [
6783
- 0,
6784
- 191,
6785
- 255
6786
- ],
6787
- "dimgray": [
6788
- 105,
6789
- 105,
6790
- 105
6791
- ],
6792
- "dimgrey": [
6793
- 105,
6794
- 105,
6795
- 105
6796
- ],
6797
- "dodgerblue": [
6798
- 30,
6799
- 144,
6800
- 255
6801
- ],
6802
- "firebrick": [
6803
- 178,
6804
- 34,
6805
- 34
6806
- ],
6807
- "floralwhite": [
6808
- 255,
6809
- 250,
6810
- 240
6811
- ],
6812
- "forestgreen": [
6813
- 34,
6814
- 139,
6815
- 34
6816
- ],
6817
- "fuchsia": [
6818
- 255,
6819
- 0,
6820
- 255
6821
- ],
6822
- "gainsboro": [
6823
- 220,
6824
- 220,
6825
- 220
6826
- ],
6827
- "ghostwhite": [
6828
- 248,
6829
- 248,
6830
- 255
6831
- ],
6832
- "gold": [
6833
- 255,
6834
- 215,
6835
- 0
6836
- ],
6837
- "goldenrod": [
6838
- 218,
6839
- 165,
6840
- 32
6841
- ],
6842
- "gray": [
6843
- 128,
6844
- 128,
6845
- 128
6846
- ],
6847
- "green": [
6848
- 0,
6849
- 128,
6850
- 0
6851
- ],
6852
- "greenyellow": [
6853
- 173,
6854
- 255,
6855
- 47
6856
- ],
6857
- "grey": [
6858
- 128,
6859
- 128,
6860
- 128
6861
- ],
6862
- "honeydew": [
6863
- 240,
6864
- 255,
6865
- 240
6866
- ],
6867
- "hotpink": [
6868
- 255,
6869
- 105,
6870
- 180
6871
- ],
6872
- "indianred": [
6873
- 205,
6874
- 92,
6875
- 92
6876
- ],
6877
- "indigo": [
6878
- 75,
6879
- 0,
6880
- 130
6881
- ],
6882
- "ivory": [
6883
- 255,
6884
- 255,
6885
- 240
6886
- ],
6887
- "khaki": [
6888
- 240,
6889
- 230,
6890
- 140
6891
- ],
6892
- "lavender": [
6893
- 230,
6894
- 230,
6895
- 250
6896
- ],
6897
- "lavenderblush": [
6898
- 255,
6899
- 240,
6900
- 245
6901
- ],
6902
- "lawngreen": [
6903
- 124,
6904
- 252,
6905
- 0
6906
- ],
6907
- "lemonchiffon": [
6908
- 255,
6909
- 250,
6910
- 205
6911
- ],
6912
- "lightblue": [
6913
- 173,
6914
- 216,
6915
- 230
6916
- ],
6917
- "lightcoral": [
6918
- 240,
6919
- 128,
6920
- 128
6921
- ],
6922
- "lightcyan": [
6923
- 224,
6924
- 255,
6925
- 255
6926
- ],
6927
- "lightgoldenrodyellow": [
6928
- 250,
6929
- 250,
6930
- 210
6931
- ],
6932
- "lightgray": [
6933
- 211,
6934
- 211,
6935
- 211
6936
- ],
6937
- "lightgreen": [
6938
- 144,
6939
- 238,
6940
- 144
6941
- ],
6942
- "lightgrey": [
6943
- 211,
6944
- 211,
6945
- 211
6946
- ],
6947
- "lightpink": [
6948
- 255,
6949
- 182,
6950
- 193
6951
- ],
6952
- "lightsalmon": [
6953
- 255,
6954
- 160,
6955
- 122
6956
- ],
6957
- "lightseagreen": [
6958
- 32,
6959
- 178,
6960
- 170
6961
- ],
6962
- "lightskyblue": [
6963
- 135,
6964
- 206,
6965
- 250
6966
- ],
6967
- "lightslategray": [
6968
- 119,
6969
- 136,
6970
- 153
6971
- ],
6972
- "lightslategrey": [
6973
- 119,
6974
- 136,
6975
- 153
6976
- ],
6977
- "lightsteelblue": [
6978
- 176,
6979
- 196,
6980
- 222
6981
- ],
6982
- "lightyellow": [
6983
- 255,
6984
- 255,
6985
- 224
6986
- ],
6987
- "lime": [
6988
- 0,
6989
- 255,
6990
- 0
6991
- ],
6992
- "limegreen": [
6993
- 50,
6994
- 205,
6995
- 50
6996
- ],
6997
- "linen": [
6998
- 250,
6999
- 240,
7000
- 230
7001
- ],
7002
- "magenta": [
7003
- 255,
7004
- 0,
7005
- 255
7006
- ],
7007
- "maroon": [
7008
- 128,
7009
- 0,
7010
- 0
7011
- ],
7012
- "mediumaquamarine": [
7013
- 102,
7014
- 205,
7015
- 170
7016
- ],
7017
- "mediumblue": [
7018
- 0,
7019
- 0,
7020
- 205
7021
- ],
7022
- "mediumorchid": [
7023
- 186,
7024
- 85,
7025
- 211
7026
- ],
7027
- "mediumpurple": [
7028
- 147,
7029
- 112,
7030
- 219
7031
- ],
7032
- "mediumseagreen": [
7033
- 60,
7034
- 179,
7035
- 113
7036
- ],
7037
- "mediumslateblue": [
7038
- 123,
7039
- 104,
7040
- 238
7041
- ],
7042
- "mediumspringgreen": [
7043
- 0,
7044
- 250,
7045
- 154
7046
- ],
7047
- "mediumturquoise": [
7048
- 72,
7049
- 209,
7050
- 204
7051
- ],
7052
- "mediumvioletred": [
7053
- 199,
7054
- 21,
7055
- 133
7056
- ],
7057
- "midnightblue": [
7058
- 25,
7059
- 25,
7060
- 112
7061
- ],
7062
- "mintcream": [
7063
- 245,
7064
- 255,
7065
- 250
7066
- ],
7067
- "mistyrose": [
7068
- 255,
7069
- 228,
7070
- 225
7071
- ],
7072
- "moccasin": [
7073
- 255,
7074
- 228,
7075
- 181
7076
- ],
7077
- "navajowhite": [
7078
- 255,
7079
- 222,
7080
- 173
7081
- ],
7082
- "navy": [
7083
- 0,
7084
- 0,
7085
- 128
7086
- ],
7087
- "oldlace": [
7088
- 253,
7089
- 245,
7090
- 230
7091
- ],
7092
- "olive": [
7093
- 128,
7094
- 128,
7095
- 0
7096
- ],
7097
- "olivedrab": [
7098
- 107,
7099
- 142,
7100
- 35
7101
- ],
7102
- "orange": [
7103
- 255,
7104
- 165,
7105
- 0
7106
- ],
7107
- "orangered": [
7108
- 255,
7109
- 69,
7110
- 0
7111
- ],
7112
- "orchid": [
7113
- 218,
7114
- 112,
7115
- 214
7116
- ],
7117
- "palegoldenrod": [
7118
- 238,
7119
- 232,
7120
- 170
7121
- ],
7122
- "palegreen": [
7123
- 152,
7124
- 251,
7125
- 152
7126
- ],
7127
- "paleturquoise": [
7128
- 175,
7129
- 238,
7130
- 238
7131
- ],
7132
- "palevioletred": [
7133
- 219,
7134
- 112,
7135
- 147
7136
- ],
7137
- "papayawhip": [
7138
- 255,
7139
- 239,
7140
- 213
7141
- ],
7142
- "peachpuff": [
7143
- 255,
7144
- 218,
7145
- 185
7146
- ],
7147
- "peru": [
7148
- 205,
7149
- 133,
7150
- 63
7151
- ],
7152
- "pink": [
7153
- 255,
7154
- 192,
7155
- 203
7156
- ],
7157
- "plum": [
7158
- 221,
7159
- 160,
7160
- 221
7161
- ],
7162
- "powderblue": [
7163
- 176,
7164
- 224,
7165
- 230
7166
- ],
7167
- "purple": [
7168
- 128,
7169
- 0,
7170
- 128
7171
- ],
7172
- "rebeccapurple": [
7173
- 102,
7174
- 51,
7175
- 153
7176
- ],
7177
- "red": [
7178
- 255,
7179
- 0,
7180
- 0
7181
- ],
7182
- "rosybrown": [
7183
- 188,
7184
- 143,
7185
- 143
7186
- ],
7187
- "royalblue": [
7188
- 65,
7189
- 105,
7190
- 225
7191
- ],
7192
- "saddlebrown": [
7193
- 139,
7194
- 69,
7195
- 19
7196
- ],
7197
- "salmon": [
7198
- 250,
7199
- 128,
7200
- 114
7201
- ],
7202
- "sandybrown": [
7203
- 244,
7204
- 164,
7205
- 96
7206
- ],
7207
- "seagreen": [
7208
- 46,
7209
- 139,
7210
- 87
7211
- ],
7212
- "seashell": [
7213
- 255,
7214
- 245,
7215
- 238
7216
- ],
7217
- "sienna": [
7218
- 160,
7219
- 82,
7220
- 45
7221
- ],
7222
- "silver": [
7223
- 192,
7224
- 192,
7225
- 192
7226
- ],
7227
- "skyblue": [
7228
- 135,
7229
- 206,
7230
- 235
7231
- ],
7232
- "slateblue": [
7233
- 106,
7234
- 90,
7235
- 205
7236
- ],
7237
- "slategray": [
7238
- 112,
7239
- 128,
7240
- 144
7241
- ],
7242
- "slategrey": [
7243
- 112,
7244
- 128,
7245
- 144
7246
- ],
7247
- "snow": [
7248
- 255,
7249
- 250,
7250
- 250
7251
- ],
7252
- "springgreen": [
7253
- 0,
7254
- 255,
7255
- 127
7256
- ],
7257
- "steelblue": [
7258
- 70,
7259
- 130,
7260
- 180
7261
- ],
7262
- "tan": [
7263
- 210,
7264
- 180,
7265
- 140
7266
- ],
7267
- "teal": [
7268
- 0,
7269
- 128,
7270
- 128
7271
- ],
7272
- "thistle": [
7273
- 216,
7274
- 191,
7275
- 216
7276
- ],
7277
- "tomato": [
7278
- 255,
7279
- 99,
7280
- 71
7281
- ],
7282
- "turquoise": [
7283
- 64,
7284
- 224,
7285
- 208
7286
- ],
7287
- "violet": [
7288
- 238,
7289
- 130,
7290
- 238
7291
- ],
7292
- "wheat": [
7293
- 245,
7294
- 222,
7295
- 179
7296
- ],
7297
- "white": [
7298
- 255,
7299
- 255,
7300
- 255
7301
- ],
7302
- "whitesmoke": [
7303
- 245,
7304
- 245,
7305
- 245
7306
- ],
7307
- "yellow": [
7308
- 255,
7309
- 255,
7310
- 0
7311
- ],
7312
- "yellowgreen": [
7313
- 154,
7314
- 205,
7315
- 50
7316
- ]
7317
- };
7318
- }));
6254
+ //#region src/module-dir.ts
6255
+ var import___vite_browser_external = /* @__PURE__ */ __toESM(require___vite_browser_external(), 1);
6256
+ var moduleDir = path.dirname(fileURLToPath$1(import.meta.url));
7319
6257
  //#endregion
7320
- //#region ../../node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/conversions.js
7321
- var require_conversions = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7322
- var cssKeywords = require_color_name();
7323
- var reverseKeywords = {};
7324
- for (const key of Object.keys(cssKeywords)) reverseKeywords[cssKeywords[key]] = key;
7325
- var convert = {
7326
- rgb: {
7327
- channels: 3,
7328
- labels: "rgb"
7329
- },
7330
- hsl: {
7331
- channels: 3,
7332
- labels: "hsl"
7333
- },
7334
- hsv: {
7335
- channels: 3,
7336
- labels: "hsv"
7337
- },
7338
- hwb: {
7339
- channels: 3,
7340
- labels: "hwb"
7341
- },
7342
- cmyk: {
7343
- channels: 4,
7344
- labels: "cmyk"
7345
- },
7346
- xyz: {
7347
- channels: 3,
7348
- labels: "xyz"
7349
- },
7350
- lab: {
7351
- channels: 3,
7352
- labels: "lab"
7353
- },
7354
- lch: {
7355
- channels: 3,
7356
- labels: "lch"
7357
- },
7358
- hex: {
7359
- channels: 1,
7360
- labels: ["hex"]
7361
- },
7362
- keyword: {
7363
- channels: 1,
7364
- labels: ["keyword"]
7365
- },
7366
- ansi16: {
7367
- channels: 1,
7368
- labels: ["ansi16"]
7369
- },
7370
- ansi256: {
7371
- channels: 1,
7372
- labels: ["ansi256"]
7373
- },
7374
- hcg: {
7375
- channels: 3,
7376
- labels: [
7377
- "h",
7378
- "c",
7379
- "g"
7380
- ]
7381
- },
7382
- apple: {
7383
- channels: 3,
7384
- labels: [
7385
- "r16",
7386
- "g16",
7387
- "b16"
7388
- ]
7389
- },
7390
- gray: {
7391
- channels: 1,
7392
- labels: ["gray"]
7393
- }
7394
- };
7395
- module.exports = convert;
7396
- for (const model of Object.keys(convert)) {
7397
- if (!("channels" in convert[model])) throw new Error("missing channels property: " + model);
7398
- if (!("labels" in convert[model])) throw new Error("missing channel labels property: " + model);
7399
- if (convert[model].labels.length !== convert[model].channels) throw new Error("channel and label counts mismatch: " + model);
7400
- const { channels, labels } = convert[model];
7401
- delete convert[model].channels;
7402
- delete convert[model].labels;
7403
- Object.defineProperty(convert[model], "channels", { value: channels });
7404
- Object.defineProperty(convert[model], "labels", { value: labels });
7405
- }
7406
- convert.rgb.hsl = function(rgb) {
7407
- const r = rgb[0] / 255;
7408
- const g = rgb[1] / 255;
7409
- const b = rgb[2] / 255;
7410
- const min = Math.min(r, g, b);
7411
- const max = Math.max(r, g, b);
7412
- const delta = max - min;
7413
- let h;
7414
- let s;
7415
- if (max === min) h = 0;
7416
- else if (r === max) h = (g - b) / delta;
7417
- else if (g === max) h = 2 + (b - r) / delta;
7418
- else if (b === max) h = 4 + (r - g) / delta;
7419
- h = Math.min(h * 60, 360);
7420
- if (h < 0) h += 360;
7421
- const l = (min + max) / 2;
7422
- if (max === min) s = 0;
7423
- else if (l <= .5) s = delta / (max + min);
7424
- else s = delta / (2 - max - min);
7425
- return [
7426
- h,
7427
- s * 100,
7428
- l * 100
7429
- ];
7430
- };
7431
- convert.rgb.hsv = function(rgb) {
7432
- let rdif;
7433
- let gdif;
7434
- let bdif;
7435
- let h;
7436
- let s;
7437
- const r = rgb[0] / 255;
7438
- const g = rgb[1] / 255;
7439
- const b = rgb[2] / 255;
7440
- const v = Math.max(r, g, b);
7441
- const diff = v - Math.min(r, g, b);
7442
- const diffc = function(c) {
7443
- return (v - c) / 6 / diff + 1 / 2;
7444
- };
7445
- if (diff === 0) {
7446
- h = 0;
7447
- s = 0;
7448
- } else {
7449
- s = diff / v;
7450
- rdif = diffc(r);
7451
- gdif = diffc(g);
7452
- bdif = diffc(b);
7453
- if (r === v) h = bdif - gdif;
7454
- else if (g === v) h = 1 / 3 + rdif - bdif;
7455
- else if (b === v) h = 2 / 3 + gdif - rdif;
7456
- if (h < 0) h += 1;
7457
- else if (h > 1) h -= 1;
7458
- }
7459
- return [
7460
- h * 360,
7461
- s * 100,
7462
- v * 100
7463
- ];
7464
- };
7465
- convert.rgb.hwb = function(rgb) {
7466
- const r = rgb[0];
7467
- const g = rgb[1];
7468
- let b = rgb[2];
7469
- const h = convert.rgb.hsl(rgb)[0];
7470
- const w = 1 / 255 * Math.min(r, Math.min(g, b));
7471
- b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
7472
- return [
7473
- h,
7474
- w * 100,
7475
- b * 100
7476
- ];
7477
- };
7478
- convert.rgb.cmyk = function(rgb) {
7479
- const r = rgb[0] / 255;
7480
- const g = rgb[1] / 255;
7481
- const b = rgb[2] / 255;
7482
- const k = Math.min(1 - r, 1 - g, 1 - b);
7483
- const c = (1 - r - k) / (1 - k) || 0;
7484
- const m = (1 - g - k) / (1 - k) || 0;
7485
- const y = (1 - b - k) / (1 - k) || 0;
7486
- return [
7487
- c * 100,
7488
- m * 100,
7489
- y * 100,
7490
- k * 100
7491
- ];
7492
- };
7493
- function comparativeDistance(x, y) {
7494
- return (x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2 + (x[2] - y[2]) ** 2;
7495
- }
7496
- convert.rgb.keyword = function(rgb) {
7497
- const reversed = reverseKeywords[rgb];
7498
- if (reversed) return reversed;
7499
- let currentClosestDistance = Infinity;
7500
- let currentClosestKeyword;
7501
- for (const keyword of Object.keys(cssKeywords)) {
7502
- const value = cssKeywords[keyword];
7503
- const distance = comparativeDistance(rgb, value);
7504
- if (distance < currentClosestDistance) {
7505
- currentClosestDistance = distance;
7506
- currentClosestKeyword = keyword;
7507
- }
7508
- }
7509
- return currentClosestKeyword;
7510
- };
7511
- convert.keyword.rgb = function(keyword) {
7512
- return cssKeywords[keyword];
7513
- };
7514
- convert.rgb.xyz = function(rgb) {
7515
- let r = rgb[0] / 255;
7516
- let g = rgb[1] / 255;
7517
- let b = rgb[2] / 255;
7518
- r = r > .04045 ? ((r + .055) / 1.055) ** 2.4 : r / 12.92;
7519
- g = g > .04045 ? ((g + .055) / 1.055) ** 2.4 : g / 12.92;
7520
- b = b > .04045 ? ((b + .055) / 1.055) ** 2.4 : b / 12.92;
7521
- const x = r * .4124 + g * .3576 + b * .1805;
7522
- const y = r * .2126 + g * .7152 + b * .0722;
7523
- const z = r * .0193 + g * .1192 + b * .9505;
7524
- return [
7525
- x * 100,
7526
- y * 100,
7527
- z * 100
7528
- ];
7529
- };
7530
- convert.rgb.lab = function(rgb) {
7531
- const xyz = convert.rgb.xyz(rgb);
7532
- let x = xyz[0];
7533
- let y = xyz[1];
7534
- let z = xyz[2];
7535
- x /= 95.047;
7536
- y /= 100;
7537
- z /= 108.883;
7538
- x = x > .008856 ? x ** (1 / 3) : 7.787 * x + 16 / 116;
7539
- y = y > .008856 ? y ** (1 / 3) : 7.787 * y + 16 / 116;
7540
- z = z > .008856 ? z ** (1 / 3) : 7.787 * z + 16 / 116;
7541
- return [
7542
- 116 * y - 16,
7543
- 500 * (x - y),
7544
- 200 * (y - z)
7545
- ];
7546
- };
7547
- convert.hsl.rgb = function(hsl) {
7548
- const h = hsl[0] / 360;
7549
- const s = hsl[1] / 100;
7550
- const l = hsl[2] / 100;
7551
- let t2;
7552
- let t3;
7553
- let val;
7554
- if (s === 0) {
7555
- val = l * 255;
7556
- return [
7557
- val,
7558
- val,
7559
- val
7560
- ];
7561
- }
7562
- if (l < .5) t2 = l * (1 + s);
7563
- else t2 = l + s - l * s;
7564
- const t1 = 2 * l - t2;
7565
- const rgb = [
7566
- 0,
7567
- 0,
7568
- 0
7569
- ];
7570
- for (let i = 0; i < 3; i++) {
7571
- t3 = h + 1 / 3 * -(i - 1);
7572
- if (t3 < 0) t3++;
7573
- if (t3 > 1) t3--;
7574
- if (6 * t3 < 1) val = t1 + (t2 - t1) * 6 * t3;
7575
- else if (2 * t3 < 1) val = t2;
7576
- else if (3 * t3 < 2) val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
7577
- else val = t1;
7578
- rgb[i] = val * 255;
7579
- }
7580
- return rgb;
7581
- };
7582
- convert.hsl.hsv = function(hsl) {
7583
- const h = hsl[0];
7584
- let s = hsl[1] / 100;
7585
- let l = hsl[2] / 100;
7586
- let smin = s;
7587
- const lmin = Math.max(l, .01);
7588
- l *= 2;
7589
- s *= l <= 1 ? l : 2 - l;
7590
- smin *= lmin <= 1 ? lmin : 2 - lmin;
7591
- const v = (l + s) / 2;
7592
- return [
7593
- h,
7594
- (l === 0 ? 2 * smin / (lmin + smin) : 2 * s / (l + s)) * 100,
7595
- v * 100
7596
- ];
7597
- };
7598
- convert.hsv.rgb = function(hsv) {
7599
- const h = hsv[0] / 60;
7600
- const s = hsv[1] / 100;
7601
- let v = hsv[2] / 100;
7602
- const hi = Math.floor(h) % 6;
7603
- const f = h - Math.floor(h);
7604
- const p = 255 * v * (1 - s);
7605
- const q = 255 * v * (1 - s * f);
7606
- const t = 255 * v * (1 - s * (1 - f));
7607
- v *= 255;
7608
- switch (hi) {
7609
- case 0: return [
7610
- v,
7611
- t,
7612
- p
7613
- ];
7614
- case 1: return [
7615
- q,
7616
- v,
7617
- p
7618
- ];
7619
- case 2: return [
7620
- p,
7621
- v,
7622
- t
7623
- ];
7624
- case 3: return [
7625
- p,
7626
- q,
7627
- v
7628
- ];
7629
- case 4: return [
7630
- t,
7631
- p,
7632
- v
7633
- ];
7634
- case 5: return [
7635
- v,
7636
- p,
7637
- q
7638
- ];
7639
- }
7640
- };
7641
- convert.hsv.hsl = function(hsv) {
7642
- const h = hsv[0];
7643
- const s = hsv[1] / 100;
7644
- const v = hsv[2] / 100;
7645
- const vmin = Math.max(v, .01);
7646
- let sl;
7647
- let l;
7648
- l = (2 - s) * v;
7649
- const lmin = (2 - s) * vmin;
7650
- sl = s * vmin;
7651
- sl /= lmin <= 1 ? lmin : 2 - lmin;
7652
- sl = sl || 0;
7653
- l /= 2;
7654
- return [
7655
- h,
7656
- sl * 100,
7657
- l * 100
7658
- ];
7659
- };
7660
- convert.hwb.rgb = function(hwb) {
7661
- const h = hwb[0] / 360;
7662
- let wh = hwb[1] / 100;
7663
- let bl = hwb[2] / 100;
7664
- const ratio = wh + bl;
7665
- let f;
7666
- if (ratio > 1) {
7667
- wh /= ratio;
7668
- bl /= ratio;
7669
- }
7670
- const i = Math.floor(6 * h);
7671
- const v = 1 - bl;
7672
- f = 6 * h - i;
7673
- if ((i & 1) !== 0) f = 1 - f;
7674
- const n = wh + f * (v - wh);
7675
- let r;
7676
- let g;
7677
- let b;
7678
- switch (i) {
7679
- default:
7680
- case 6:
7681
- case 0:
7682
- r = v;
7683
- g = n;
7684
- b = wh;
7685
- break;
7686
- case 1:
7687
- r = n;
7688
- g = v;
7689
- b = wh;
7690
- break;
7691
- case 2:
7692
- r = wh;
7693
- g = v;
7694
- b = n;
7695
- break;
7696
- case 3:
7697
- r = wh;
7698
- g = n;
7699
- b = v;
7700
- break;
7701
- case 4:
7702
- r = n;
7703
- g = wh;
7704
- b = v;
7705
- break;
7706
- case 5:
7707
- r = v;
7708
- g = wh;
7709
- b = n;
7710
- break;
7711
- }
7712
- return [
7713
- r * 255,
7714
- g * 255,
7715
- b * 255
7716
- ];
7717
- };
7718
- convert.cmyk.rgb = function(cmyk) {
7719
- const c = cmyk[0] / 100;
7720
- const m = cmyk[1] / 100;
7721
- const y = cmyk[2] / 100;
7722
- const k = cmyk[3] / 100;
7723
- const r = 1 - Math.min(1, c * (1 - k) + k);
7724
- const g = 1 - Math.min(1, m * (1 - k) + k);
7725
- const b = 1 - Math.min(1, y * (1 - k) + k);
7726
- return [
7727
- r * 255,
7728
- g * 255,
7729
- b * 255
7730
- ];
7731
- };
7732
- convert.xyz.rgb = function(xyz) {
7733
- const x = xyz[0] / 100;
7734
- const y = xyz[1] / 100;
7735
- const z = xyz[2] / 100;
7736
- let r;
7737
- let g;
7738
- let b;
7739
- r = x * 3.2406 + y * -1.5372 + z * -.4986;
7740
- g = x * -.9689 + y * 1.8758 + z * .0415;
7741
- b = x * .0557 + y * -.204 + z * 1.057;
7742
- r = r > .0031308 ? 1.055 * r ** (1 / 2.4) - .055 : r * 12.92;
7743
- g = g > .0031308 ? 1.055 * g ** (1 / 2.4) - .055 : g * 12.92;
7744
- b = b > .0031308 ? 1.055 * b ** (1 / 2.4) - .055 : b * 12.92;
7745
- r = Math.min(Math.max(0, r), 1);
7746
- g = Math.min(Math.max(0, g), 1);
7747
- b = Math.min(Math.max(0, b), 1);
7748
- return [
7749
- r * 255,
7750
- g * 255,
7751
- b * 255
7752
- ];
7753
- };
7754
- convert.xyz.lab = function(xyz) {
7755
- let x = xyz[0];
7756
- let y = xyz[1];
7757
- let z = xyz[2];
7758
- x /= 95.047;
7759
- y /= 100;
7760
- z /= 108.883;
7761
- x = x > .008856 ? x ** (1 / 3) : 7.787 * x + 16 / 116;
7762
- y = y > .008856 ? y ** (1 / 3) : 7.787 * y + 16 / 116;
7763
- z = z > .008856 ? z ** (1 / 3) : 7.787 * z + 16 / 116;
7764
- return [
7765
- 116 * y - 16,
7766
- 500 * (x - y),
7767
- 200 * (y - z)
7768
- ];
7769
- };
7770
- convert.lab.xyz = function(lab) {
7771
- const l = lab[0];
7772
- const a = lab[1];
7773
- const b = lab[2];
7774
- let x;
7775
- let y;
7776
- let z;
7777
- y = (l + 16) / 116;
7778
- x = a / 500 + y;
7779
- z = y - b / 200;
7780
- const y2 = y ** 3;
7781
- const x2 = x ** 3;
7782
- const z2 = z ** 3;
7783
- y = y2 > .008856 ? y2 : (y - 16 / 116) / 7.787;
7784
- x = x2 > .008856 ? x2 : (x - 16 / 116) / 7.787;
7785
- z = z2 > .008856 ? z2 : (z - 16 / 116) / 7.787;
7786
- x *= 95.047;
7787
- y *= 100;
7788
- z *= 108.883;
7789
- return [
7790
- x,
7791
- y,
7792
- z
7793
- ];
7794
- };
7795
- convert.lab.lch = function(lab) {
7796
- const l = lab[0];
7797
- const a = lab[1];
7798
- const b = lab[2];
7799
- let h;
7800
- h = Math.atan2(b, a) * 360 / 2 / Math.PI;
7801
- if (h < 0) h += 360;
7802
- return [
7803
- l,
7804
- Math.sqrt(a * a + b * b),
7805
- h
7806
- ];
7807
- };
7808
- convert.lch.lab = function(lch) {
7809
- const l = lch[0];
7810
- const c = lch[1];
7811
- const hr = lch[2] / 360 * 2 * Math.PI;
7812
- return [
7813
- l,
7814
- c * Math.cos(hr),
7815
- c * Math.sin(hr)
7816
- ];
7817
- };
7818
- convert.rgb.ansi16 = function(args, saturation = null) {
7819
- const [r, g, b] = args;
7820
- let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation;
7821
- value = Math.round(value / 50);
7822
- if (value === 0) return 30;
7823
- let ansi = 30 + (Math.round(b / 255) << 2 | Math.round(g / 255) << 1 | Math.round(r / 255));
7824
- if (value === 2) ansi += 60;
7825
- return ansi;
7826
- };
7827
- convert.hsv.ansi16 = function(args) {
7828
- return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
7829
- };
7830
- convert.rgb.ansi256 = function(args) {
7831
- const r = args[0];
7832
- const g = args[1];
7833
- const b = args[2];
7834
- if (r === g && g === b) {
7835
- if (r < 8) return 16;
7836
- if (r > 248) return 231;
7837
- return Math.round((r - 8) / 247 * 24) + 232;
7838
- }
7839
- return 16 + 36 * Math.round(r / 255 * 5) + 6 * Math.round(g / 255 * 5) + Math.round(b / 255 * 5);
7840
- };
7841
- convert.ansi16.rgb = function(args) {
7842
- let color = args % 10;
7843
- if (color === 0 || color === 7) {
7844
- if (args > 50) color += 3.5;
7845
- color = color / 10.5 * 255;
7846
- return [
7847
- color,
7848
- color,
7849
- color
7850
- ];
7851
- }
7852
- const mult = (~~(args > 50) + 1) * .5;
7853
- return [
7854
- (color & 1) * mult * 255,
7855
- (color >> 1 & 1) * mult * 255,
7856
- (color >> 2 & 1) * mult * 255
7857
- ];
7858
- };
7859
- convert.ansi256.rgb = function(args) {
7860
- if (args >= 232) {
7861
- const c = (args - 232) * 10 + 8;
7862
- return [
7863
- c,
7864
- c,
7865
- c
7866
- ];
7867
- }
7868
- args -= 16;
7869
- let rem;
7870
- return [
7871
- Math.floor(args / 36) / 5 * 255,
7872
- Math.floor((rem = args % 36) / 6) / 5 * 255,
7873
- rem % 6 / 5 * 255
7874
- ];
7875
- };
7876
- convert.rgb.hex = function(args) {
7877
- const string = (((Math.round(args[0]) & 255) << 16) + ((Math.round(args[1]) & 255) << 8) + (Math.round(args[2]) & 255)).toString(16).toUpperCase();
7878
- return "000000".substring(string.length) + string;
7879
- };
7880
- convert.hex.rgb = function(args) {
7881
- const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
7882
- if (!match) return [
7883
- 0,
7884
- 0,
7885
- 0
7886
- ];
7887
- let colorString = match[0];
7888
- if (match[0].length === 3) colorString = colorString.split("").map((char) => {
7889
- return char + char;
7890
- }).join("");
7891
- const integer = parseInt(colorString, 16);
7892
- return [
7893
- integer >> 16 & 255,
7894
- integer >> 8 & 255,
7895
- integer & 255
7896
- ];
7897
- };
7898
- convert.rgb.hcg = function(rgb) {
7899
- const r = rgb[0] / 255;
7900
- const g = rgb[1] / 255;
7901
- const b = rgb[2] / 255;
7902
- const max = Math.max(Math.max(r, g), b);
7903
- const min = Math.min(Math.min(r, g), b);
7904
- const chroma = max - min;
7905
- let grayscale;
7906
- let hue;
7907
- if (chroma < 1) grayscale = min / (1 - chroma);
7908
- else grayscale = 0;
7909
- if (chroma <= 0) hue = 0;
7910
- else if (max === r) hue = (g - b) / chroma % 6;
7911
- else if (max === g) hue = 2 + (b - r) / chroma;
7912
- else hue = 4 + (r - g) / chroma;
7913
- hue /= 6;
7914
- hue %= 1;
7915
- return [
7916
- hue * 360,
7917
- chroma * 100,
7918
- grayscale * 100
7919
- ];
7920
- };
7921
- convert.hsl.hcg = function(hsl) {
7922
- const s = hsl[1] / 100;
7923
- const l = hsl[2] / 100;
7924
- const c = l < .5 ? 2 * s * l : 2 * s * (1 - l);
7925
- let f = 0;
7926
- if (c < 1) f = (l - .5 * c) / (1 - c);
7927
- return [
7928
- hsl[0],
7929
- c * 100,
7930
- f * 100
7931
- ];
7932
- };
7933
- convert.hsv.hcg = function(hsv) {
7934
- const s = hsv[1] / 100;
7935
- const v = hsv[2] / 100;
7936
- const c = s * v;
7937
- let f = 0;
7938
- if (c < 1) f = (v - c) / (1 - c);
7939
- return [
7940
- hsv[0],
7941
- c * 100,
7942
- f * 100
7943
- ];
7944
- };
7945
- convert.hcg.rgb = function(hcg) {
7946
- const h = hcg[0] / 360;
7947
- const c = hcg[1] / 100;
7948
- const g = hcg[2] / 100;
7949
- if (c === 0) return [
7950
- g * 255,
7951
- g * 255,
7952
- g * 255
7953
- ];
7954
- const pure = [
7955
- 0,
7956
- 0,
7957
- 0
7958
- ];
7959
- const hi = h % 1 * 6;
7960
- const v = hi % 1;
7961
- const w = 1 - v;
7962
- let mg = 0;
7963
- switch (Math.floor(hi)) {
7964
- case 0:
7965
- pure[0] = 1;
7966
- pure[1] = v;
7967
- pure[2] = 0;
7968
- break;
7969
- case 1:
7970
- pure[0] = w;
7971
- pure[1] = 1;
7972
- pure[2] = 0;
7973
- break;
7974
- case 2:
7975
- pure[0] = 0;
7976
- pure[1] = 1;
7977
- pure[2] = v;
7978
- break;
7979
- case 3:
7980
- pure[0] = 0;
7981
- pure[1] = w;
7982
- pure[2] = 1;
7983
- break;
7984
- case 4:
7985
- pure[0] = v;
7986
- pure[1] = 0;
7987
- pure[2] = 1;
7988
- break;
7989
- default:
7990
- pure[0] = 1;
7991
- pure[1] = 0;
7992
- pure[2] = w;
7993
- }
7994
- mg = (1 - c) * g;
7995
- return [
7996
- (c * pure[0] + mg) * 255,
7997
- (c * pure[1] + mg) * 255,
7998
- (c * pure[2] + mg) * 255
7999
- ];
8000
- };
8001
- convert.hcg.hsv = function(hcg) {
8002
- const c = hcg[1] / 100;
8003
- const v = c + hcg[2] / 100 * (1 - c);
8004
- let f = 0;
8005
- if (v > 0) f = c / v;
8006
- return [
8007
- hcg[0],
8008
- f * 100,
8009
- v * 100
8010
- ];
8011
- };
8012
- convert.hcg.hsl = function(hcg) {
8013
- const c = hcg[1] / 100;
8014
- const l = hcg[2] / 100 * (1 - c) + .5 * c;
8015
- let s = 0;
8016
- if (l > 0 && l < .5) s = c / (2 * l);
8017
- else if (l >= .5 && l < 1) s = c / (2 * (1 - l));
8018
- return [
8019
- hcg[0],
8020
- s * 100,
8021
- l * 100
8022
- ];
8023
- };
8024
- convert.hcg.hwb = function(hcg) {
8025
- const c = hcg[1] / 100;
8026
- const v = c + hcg[2] / 100 * (1 - c);
8027
- return [
8028
- hcg[0],
8029
- (v - c) * 100,
8030
- (1 - v) * 100
8031
- ];
8032
- };
8033
- convert.hwb.hcg = function(hwb) {
8034
- const w = hwb[1] / 100;
8035
- const v = 1 - hwb[2] / 100;
8036
- const c = v - w;
8037
- let g = 0;
8038
- if (c < 1) g = (v - c) / (1 - c);
8039
- return [
8040
- hwb[0],
8041
- c * 100,
8042
- g * 100
8043
- ];
8044
- };
8045
- convert.apple.rgb = function(apple) {
8046
- return [
8047
- apple[0] / 65535 * 255,
8048
- apple[1] / 65535 * 255,
8049
- apple[2] / 65535 * 255
8050
- ];
8051
- };
8052
- convert.rgb.apple = function(rgb) {
8053
- return [
8054
- rgb[0] / 255 * 65535,
8055
- rgb[1] / 255 * 65535,
8056
- rgb[2] / 255 * 65535
8057
- ];
8058
- };
8059
- convert.gray.rgb = function(args) {
8060
- return [
8061
- args[0] / 100 * 255,
8062
- args[0] / 100 * 255,
8063
- args[0] / 100 * 255
8064
- ];
8065
- };
8066
- convert.gray.hsl = function(args) {
8067
- return [
8068
- 0,
8069
- 0,
8070
- args[0]
6258
+ //#region src/cli-helpers.ts
6259
+ /**
6260
+ * Which package manager installed this project, read off its lockfile.
6261
+ *
6262
+ * Every remedy for a blocked build script is package-manager specific, and
6263
+ * naming the wrong one is the same failure as naming none: `pnpm approve-builds`
6264
+ * is not a thing an npm user can run, and `pnpm.onlyBuiltDependencies` is a key
6265
+ * npm does not read. This existed as a pnpm-only message for long enough that
6266
+ * npm 12 — which blocks dependency lifecycle scripts by default, the way pnpm 10
6267
+ * does — could ship and leave every npm reader three unfollowable commands deep.
6268
+ *
6269
+ * The lockfile, not `npm_config_user_agent`: the question is how the project's
6270
+ * `node_modules` was built, not which binary happens to be invoking us. Walks up
6271
+ * because commands run from `backend/` in a scaffolded project, and the lockfile
6272
+ * is at the workspace root.
6273
+ */
6274
+ function detectProjectPackageManager(startDir = process.cwd()) {
6275
+ const lockfiles = [
6276
+ ["pnpm-lock.yaml", "pnpm"],
6277
+ ["bun.lock", "bun"],
6278
+ ["bun.lockb", "bun"],
6279
+ ["yarn.lock", "yarn"],
6280
+ ["package-lock.json", "npm"]
6281
+ ];
6282
+ let dir = path.resolve(startDir);
6283
+ while (true) {
6284
+ for (const [file, manager] of lockfiles) if (fs.existsSync(path.join(dir, file))) return manager;
6285
+ const parent = path.dirname(dir);
6286
+ if (parent === dir) return "unknown";
6287
+ dir = parent;
6288
+ }
6289
+ }
6290
+ /**
6291
+ * How to let `@ariga/atlas` run its `preinstall`, in the reader's own package
6292
+ * manager.
6293
+ *
6294
+ * Returns the lines to print after "the binary is missing but the package is
6295
+ * installed". Kept next to {@link detectProjectPackageManager} so the two move
6296
+ * together, and returned rather than printed so it can be asserted on.
6297
+ */
6298
+ function describeBuildScriptRemedy(packageName, manager = detectProjectPackageManager()) {
6299
+ switch (manager) {
6300
+ case "npm": return [
6301
+ ` npm install-scripts approve ${packageName}`,
6302
+ "",
6303
+ " or, to record it in the project (what `rebase init` scaffolds):",
6304
+ "",
6305
+ " // package.json",
6306
+ ` "allowScripts": { "${packageName}": true }`,
6307
+ "",
6308
+ " Then re-run `npm install`."
8071
6309
  ];
8072
- };
8073
- convert.gray.hsv = convert.gray.hsl;
8074
- convert.gray.hwb = function(gray) {
8075
- return [
8076
- 0,
8077
- 100,
8078
- gray[0]
6310
+ case "yarn": return [
6311
+ " // .yarnrc.yml",
6312
+ " enableScripts: true",
6313
+ "",
6314
+ " Then re-run `yarn install`."
8079
6315
  ];
8080
- };
8081
- convert.gray.cmyk = function(gray) {
8082
- return [
8083
- 0,
8084
- 0,
8085
- 0,
8086
- gray[0]
6316
+ case "bun": return [
6317
+ " // package.json",
6318
+ ` "trustedDependencies": ["${packageName}"]`,
6319
+ "",
6320
+ " Then re-run `bun install`."
8087
6321
  ];
8088
- };
8089
- convert.gray.lab = function(gray) {
8090
- return [
8091
- gray[0],
8092
- 0,
8093
- 0
6322
+ default: return [
6323
+ " pnpm approve-builds",
6324
+ "",
6325
+ " or, to record it in the project (what `rebase init` scaffolds):",
6326
+ "",
6327
+ " // package.json",
6328
+ ` "pnpm": { "onlyBuiltDependencies": ["${packageName}"] }`,
6329
+ "",
6330
+ " Then re-run `pnpm install`."
8094
6331
  ];
8095
- };
8096
- convert.gray.hex = function(gray) {
8097
- const val = Math.round(gray[0] / 100 * 255) & 255;
8098
- const string = ((val << 16) + (val << 8) + val).toString(16).toUpperCase();
8099
- return "000000".substring(string.length) + string;
8100
- };
8101
- convert.rgb.gray = function(rgb) {
8102
- return [(rgb[0] + rgb[1] + rgb[2]) / 3 / 255 * 100];
8103
- };
8104
- }));
8105
- //#endregion
8106
- //#region ../../node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/route.js
8107
- var require_route = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8108
- var conversions = require_conversions();
8109
- function buildGraph() {
8110
- const graph = {};
8111
- const models = Object.keys(conversions);
8112
- for (let len = models.length, i = 0; i < len; i++) graph[models[i]] = {
8113
- distance: -1,
8114
- parent: null
8115
- };
8116
- return graph;
8117
- }
8118
- function deriveBFS(fromModel) {
8119
- const graph = buildGraph();
8120
- const queue = [fromModel];
8121
- graph[fromModel].distance = 0;
8122
- while (queue.length) {
8123
- const current = queue.pop();
8124
- const adjacents = Object.keys(conversions[current]);
8125
- for (let len = adjacents.length, i = 0; i < len; i++) {
8126
- const adjacent = adjacents[i];
8127
- const node = graph[adjacent];
8128
- if (node.distance === -1) {
8129
- node.distance = graph[current].distance + 1;
8130
- node.parent = current;
8131
- queue.unshift(adjacent);
8132
- }
8133
- }
8134
- }
8135
- return graph;
8136
6332
  }
8137
- function link(from, to) {
8138
- return function(args) {
8139
- return to(from(args));
8140
- };
6333
+ }
6334
+ /**
6335
+ * "Install again, from scratch", in the reader's own package manager.
6336
+ *
6337
+ * For the `bin-link-missing` state: the tree is half-written, and re-resolving
6338
+ * it is what recreates the `.bin` shim. `--force` on pnpm is what makes it
6339
+ * relink rather than decide the tree is already up to date.
6340
+ */
6341
+ function describeReinstallCommand(manager = detectProjectPackageManager()) {
6342
+ switch (manager) {
6343
+ case "npm": return "rm -rf node_modules && npm install";
6344
+ case "yarn": return "yarn install --force";
6345
+ case "bun": return "rm -rf node_modules && bun install";
6346
+ default: return "pnpm install --force";
8141
6347
  }
8142
- function wrapConversion(toModel, graph) {
8143
- const path = [graph[toModel].parent, toModel];
8144
- let fn = conversions[graph[toModel].parent][toModel];
8145
- let cur = graph[toModel].parent;
8146
- while (graph[cur].parent) {
8147
- path.unshift(graph[cur].parent);
8148
- fn = link(conversions[graph[cur].parent][cur], fn);
8149
- cur = graph[cur].parent;
8150
- }
8151
- fn.conversion = path;
8152
- return fn;
8153
- }
8154
- module.exports = function(fromModel) {
8155
- const graph = deriveBFS(fromModel);
8156
- const conversion = {};
8157
- const models = Object.keys(graph);
8158
- for (let len = models.length, i = 0; i < len; i++) {
8159
- const toModel = models[i];
8160
- if (graph[toModel].parent === null) continue;
8161
- conversion[toModel] = wrapConversion(toModel, graph);
8162
- }
8163
- return conversion;
8164
- };
8165
- }));
8166
- //#endregion
8167
- //#region ../../node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/index.js
8168
- var require_color_convert = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8169
- var conversions = require_conversions();
8170
- var route = require_route();
8171
- var convert = {};
8172
- var models = Object.keys(conversions);
8173
- function wrapRaw(fn) {
8174
- const wrappedFn = function(...args) {
8175
- const arg0 = args[0];
8176
- if (arg0 === void 0 || arg0 === null) return arg0;
8177
- if (arg0.length > 1) args = arg0;
8178
- return fn(args);
8179
- };
8180
- if ("conversion" in fn) wrappedFn.conversion = fn.conversion;
8181
- return wrappedFn;
8182
- }
8183
- function wrapRounded(fn) {
8184
- const wrappedFn = function(...args) {
8185
- const arg0 = args[0];
8186
- if (arg0 === void 0 || arg0 === null) return arg0;
8187
- if (arg0.length > 1) args = arg0;
8188
- const result = fn(args);
8189
- if (typeof result === "object") for (let len = result.length, i = 0; i < len; i++) result[i] = Math.round(result[i]);
8190
- return result;
8191
- };
8192
- if ("conversion" in fn) wrappedFn.conversion = fn.conversion;
8193
- return wrappedFn;
8194
- }
8195
- models.forEach((fromModel) => {
8196
- convert[fromModel] = {};
8197
- Object.defineProperty(convert[fromModel], "channels", { value: conversions[fromModel].channels });
8198
- Object.defineProperty(convert[fromModel], "labels", { value: conversions[fromModel].labels });
8199
- const routes = route(fromModel);
8200
- Object.keys(routes).forEach((toModel) => {
8201
- const fn = routes[toModel];
8202
- convert[fromModel][toModel] = wrapRounded(fn);
8203
- convert[fromModel][toModel].raw = wrapRaw(fn);
8204
- });
8205
- });
8206
- module.exports = convert;
8207
- }));
8208
- //#endregion
8209
- //#region ../../node_modules/.pnpm/ansi-styles@4.3.0/node_modules/ansi-styles/index.js
8210
- var require_ansi_styles = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8211
- var wrapAnsi16 = (fn, offset) => (...args) => {
8212
- return `\u001B[${fn(...args) + offset}m`;
8213
- };
8214
- var wrapAnsi256 = (fn, offset) => (...args) => {
8215
- const code = fn(...args);
8216
- return `\u001B[${38 + offset};5;${code}m`;
8217
- };
8218
- var wrapAnsi16m = (fn, offset) => (...args) => {
8219
- const rgb = fn(...args);
8220
- return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
8221
- };
8222
- var ansi2ansi = (n) => n;
8223
- var rgb2rgb = (r, g, b) => [
8224
- r,
8225
- g,
8226
- b
8227
- ];
8228
- var setLazyProperty = (object, property, get) => {
8229
- Object.defineProperty(object, property, {
8230
- get: () => {
8231
- const value = get();
8232
- Object.defineProperty(object, property, {
8233
- value,
8234
- enumerable: true,
8235
- configurable: true
8236
- });
8237
- return value;
8238
- },
8239
- enumerable: true,
8240
- configurable: true
8241
- });
8242
- };
8243
- /** @type {typeof import('color-convert')} */
8244
- var colorConvert;
8245
- var makeDynamicStyles = (wrap, targetSpace, identity, isBackground) => {
8246
- if (colorConvert === void 0) colorConvert = require_color_convert();
8247
- const offset = isBackground ? 10 : 0;
8248
- const styles = {};
8249
- for (const [sourceSpace, suite] of Object.entries(colorConvert)) {
8250
- const name = sourceSpace === "ansi16" ? "ansi" : sourceSpace;
8251
- if (sourceSpace === targetSpace) styles[name] = wrap(identity, offset);
8252
- else if (typeof suite === "object") styles[name] = wrap(suite[targetSpace], offset);
8253
- }
8254
- return styles;
8255
- };
8256
- function assembleStyles() {
8257
- const codes = /* @__PURE__ */ new Map();
8258
- const styles = {
8259
- modifier: {
8260
- reset: [0, 0],
8261
- bold: [1, 22],
8262
- dim: [2, 22],
8263
- italic: [3, 23],
8264
- underline: [4, 24],
8265
- inverse: [7, 27],
8266
- hidden: [8, 28],
8267
- strikethrough: [9, 29]
8268
- },
8269
- color: {
8270
- black: [30, 39],
8271
- red: [31, 39],
8272
- green: [32, 39],
8273
- yellow: [33, 39],
8274
- blue: [34, 39],
8275
- magenta: [35, 39],
8276
- cyan: [36, 39],
8277
- white: [37, 39],
8278
- blackBright: [90, 39],
8279
- redBright: [91, 39],
8280
- greenBright: [92, 39],
8281
- yellowBright: [93, 39],
8282
- blueBright: [94, 39],
8283
- magentaBright: [95, 39],
8284
- cyanBright: [96, 39],
8285
- whiteBright: [97, 39]
8286
- },
8287
- bgColor: {
8288
- bgBlack: [40, 49],
8289
- bgRed: [41, 49],
8290
- bgGreen: [42, 49],
8291
- bgYellow: [43, 49],
8292
- bgBlue: [44, 49],
8293
- bgMagenta: [45, 49],
8294
- bgCyan: [46, 49],
8295
- bgWhite: [47, 49],
8296
- bgBlackBright: [100, 49],
8297
- bgRedBright: [101, 49],
8298
- bgGreenBright: [102, 49],
8299
- bgYellowBright: [103, 49],
8300
- bgBlueBright: [104, 49],
8301
- bgMagentaBright: [105, 49],
8302
- bgCyanBright: [106, 49],
8303
- bgWhiteBright: [107, 49]
8304
- }
8305
- };
8306
- styles.color.gray = styles.color.blackBright;
8307
- styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
8308
- styles.color.grey = styles.color.blackBright;
8309
- styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
8310
- for (const [groupName, group] of Object.entries(styles)) {
8311
- for (const [styleName, style] of Object.entries(group)) {
8312
- styles[styleName] = {
8313
- open: `\u001B[${style[0]}m`,
8314
- close: `\u001B[${style[1]}m`
8315
- };
8316
- group[styleName] = styles[styleName];
8317
- codes.set(style[0], style[1]);
8318
- }
8319
- Object.defineProperty(styles, groupName, {
8320
- value: group,
8321
- enumerable: false
8322
- });
8323
- }
8324
- Object.defineProperty(styles, "codes", {
8325
- value: codes,
8326
- enumerable: false
8327
- });
8328
- styles.color.close = "\x1B[39m";
8329
- styles.bgColor.close = "\x1B[49m";
8330
- setLazyProperty(styles.color, "ansi", () => makeDynamicStyles(wrapAnsi16, "ansi16", ansi2ansi, false));
8331
- setLazyProperty(styles.color, "ansi256", () => makeDynamicStyles(wrapAnsi256, "ansi256", ansi2ansi, false));
8332
- setLazyProperty(styles.color, "ansi16m", () => makeDynamicStyles(wrapAnsi16m, "rgb", rgb2rgb, false));
8333
- setLazyProperty(styles.bgColor, "ansi", () => makeDynamicStyles(wrapAnsi16, "ansi16", ansi2ansi, true));
8334
- setLazyProperty(styles.bgColor, "ansi256", () => makeDynamicStyles(wrapAnsi256, "ansi256", ansi2ansi, true));
8335
- setLazyProperty(styles.bgColor, "ansi16m", () => makeDynamicStyles(wrapAnsi16m, "rgb", rgb2rgb, true));
8336
- return styles;
8337
- }
8338
- Object.defineProperty(module, "exports", {
8339
- enumerable: true,
8340
- get: assembleStyles
8341
- });
8342
- }));
8343
- //#endregion
8344
- //#region ../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/browser.js
8345
- var require_browser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8346
- module.exports = {
8347
- stdout: false,
8348
- stderr: false
8349
- };
8350
- }));
8351
- //#endregion
8352
- //#region ../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/util.js
8353
- var require_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8354
- var stringReplaceAll = (string, substring, replacer) => {
8355
- let index = string.indexOf(substring);
8356
- if (index === -1) return string;
8357
- const substringLength = substring.length;
8358
- let endIndex = 0;
8359
- let returnValue = "";
8360
- do {
8361
- returnValue += string.substr(endIndex, index - endIndex) + substring + replacer;
8362
- endIndex = index + substringLength;
8363
- index = string.indexOf(substring, endIndex);
8364
- } while (index !== -1);
8365
- returnValue += string.substr(endIndex);
8366
- return returnValue;
8367
- };
8368
- var stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => {
8369
- let endIndex = 0;
8370
- let returnValue = "";
8371
- do {
8372
- const gotCR = string[index - 1] === "\r";
8373
- returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
8374
- endIndex = index + 1;
8375
- index = string.indexOf("\n", endIndex);
8376
- } while (index !== -1);
8377
- returnValue += string.substr(endIndex);
8378
- return returnValue;
8379
- };
8380
- module.exports = {
8381
- stringReplaceAll,
8382
- stringEncaseCRLFWithFirstIndex
8383
- };
8384
- }));
8385
- //#endregion
8386
- //#region ../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/templates.js
8387
- var require_templates = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8388
- var TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi;
8389
- var STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g;
8390
- var STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/;
8391
- var ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi;
8392
- var ESCAPES = /* @__PURE__ */ new Map([
8393
- ["n", "\n"],
8394
- ["r", "\r"],
8395
- ["t", " "],
8396
- ["b", "\b"],
8397
- ["f", "\f"],
8398
- ["v", "\v"],
8399
- ["0", "\0"],
8400
- ["\\", "\\"],
8401
- ["e", "\x1B"],
8402
- ["a", "\x07"]
8403
- ]);
8404
- function unescape(c) {
8405
- const u = c[0] === "u";
8406
- const bracket = c[1] === "{";
8407
- if (u && !bracket && c.length === 5 || c[0] === "x" && c.length === 3) return String.fromCharCode(parseInt(c.slice(1), 16));
8408
- if (u && bracket) return String.fromCodePoint(parseInt(c.slice(2, -1), 16));
8409
- return ESCAPES.get(c) || c;
8410
- }
8411
- function parseArguments(name, arguments_) {
8412
- const results = [];
8413
- const chunks = arguments_.trim().split(/\s*,\s*/g);
8414
- let matches;
8415
- for (const chunk of chunks) {
8416
- const number = Number(chunk);
8417
- if (!Number.isNaN(number)) results.push(number);
8418
- else if (matches = chunk.match(STRING_REGEX)) results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character));
8419
- else throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`);
8420
- }
8421
- return results;
8422
- }
8423
- function parseStyle(style) {
8424
- STYLE_REGEX.lastIndex = 0;
8425
- const results = [];
8426
- let matches;
8427
- while ((matches = STYLE_REGEX.exec(style)) !== null) {
8428
- const name = matches[1];
8429
- if (matches[2]) {
8430
- const args = parseArguments(name, matches[2]);
8431
- results.push([name].concat(args));
8432
- } else results.push([name]);
8433
- }
8434
- return results;
8435
- }
8436
- function buildStyle(chalk, styles) {
8437
- const enabled = {};
8438
- for (const layer of styles) for (const style of layer.styles) enabled[style[0]] = layer.inverse ? null : style.slice(1);
8439
- let current = chalk;
8440
- for (const [styleName, styles] of Object.entries(enabled)) {
8441
- if (!Array.isArray(styles)) continue;
8442
- if (!(styleName in current)) throw new Error(`Unknown Chalk style: ${styleName}`);
8443
- current = styles.length > 0 ? current[styleName](...styles) : current[styleName];
8444
- }
8445
- return current;
8446
- }
8447
- module.exports = (chalk, temporary) => {
8448
- const styles = [];
8449
- const chunks = [];
8450
- let chunk = [];
8451
- temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => {
8452
- if (escapeCharacter) chunk.push(unescape(escapeCharacter));
8453
- else if (style) {
8454
- const string = chunk.join("");
8455
- chunk = [];
8456
- chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string));
8457
- styles.push({
8458
- inverse,
8459
- styles: parseStyle(style)
8460
- });
8461
- } else if (close) {
8462
- if (styles.length === 0) throw new Error("Found extraneous } in Chalk template literal");
8463
- chunks.push(buildStyle(chalk, styles)(chunk.join("")));
8464
- chunk = [];
8465
- styles.pop();
8466
- } else chunk.push(character);
8467
- });
8468
- chunks.push(chunk.join(""));
8469
- if (styles.length > 0) {
8470
- const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? "" : "s"} (\`}\`)`;
8471
- throw new Error(errMessage);
8472
- }
8473
- return chunks.join("");
8474
- };
8475
- }));
8476
- //#endregion
8477
- //#region ../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/index.js
8478
- var require_source = /* @__PURE__ */ __commonJSMin(((exports, module) => {
8479
- var ansiStyles = require_ansi_styles();
8480
- var { stdout: stdoutColor, stderr: stderrColor } = require_browser();
8481
- var { stringReplaceAll, stringEncaseCRLFWithFirstIndex } = require_util();
8482
- var { isArray } = Array;
8483
- var levelMapping = [
8484
- "ansi",
8485
- "ansi",
8486
- "ansi256",
8487
- "ansi16m"
8488
- ];
8489
- var styles = Object.create(null);
8490
- var applyOptions = (object, options = {}) => {
8491
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) throw new Error("The `level` option should be an integer from 0 to 3");
8492
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
8493
- object.level = options.level === void 0 ? colorLevel : options.level;
8494
- };
8495
- var ChalkClass = class {
8496
- constructor(options) {
8497
- return chalkFactory(options);
8498
- }
8499
- };
8500
- var chalkFactory = (options) => {
8501
- const chalk = {};
8502
- applyOptions(chalk, options);
8503
- chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_);
8504
- Object.setPrototypeOf(chalk, Chalk.prototype);
8505
- Object.setPrototypeOf(chalk.template, chalk);
8506
- chalk.template.constructor = () => {
8507
- throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
8508
- };
8509
- chalk.template.Instance = ChalkClass;
8510
- return chalk.template;
8511
- };
8512
- function Chalk(options) {
8513
- return chalkFactory(options);
6348
+ }
6349
+ /** `add <pkg>` as a dev dependency, in the reader's own package manager. */
6350
+ function describeDevAddCommand(packageName, manager = detectProjectPackageManager()) {
6351
+ switch (manager) {
6352
+ case "npm": return `npm install -D ${packageName}`;
6353
+ case "yarn": return `yarn add -D ${packageName}`;
6354
+ case "bun": return `bun add -d ${packageName}`;
6355
+ default: return `pnpm add -D ${packageName}`;
8514
6356
  }
8515
- for (const [styleName, style] of Object.entries(ansiStyles)) styles[styleName] = { get() {
8516
- const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty);
8517
- Object.defineProperty(this, styleName, { value: builder });
8518
- return builder;
8519
- } };
8520
- styles.visible = { get() {
8521
- const builder = createBuilder(this, this._styler, true);
8522
- Object.defineProperty(this, "visible", { value: builder });
8523
- return builder;
8524
- } };
8525
- var usedModels = [
8526
- "rgb",
8527
- "hex",
8528
- "keyword",
8529
- "hsl",
8530
- "hsv",
8531
- "hwb",
8532
- "ansi",
8533
- "ansi256"
8534
- ];
8535
- for (const model of usedModels) styles[model] = { get() {
8536
- const { level } = this;
8537
- return function(...arguments_) {
8538
- const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler);
8539
- return createBuilder(this, styler, this._isEmpty);
8540
- };
8541
- } };
8542
- for (const model of usedModels) {
8543
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
8544
- styles[bgModel] = { get() {
8545
- const { level } = this;
8546
- return function(...arguments_) {
8547
- const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler);
8548
- return createBuilder(this, styler, this._isEmpty);
8549
- };
8550
- } };
8551
- }
8552
- var proto = Object.defineProperties(() => {}, {
8553
- ...styles,
8554
- level: {
8555
- enumerable: true,
8556
- get() {
8557
- return this._generator.level;
8558
- },
8559
- set(level) {
8560
- this._generator.level = level;
8561
- }
8562
- }
8563
- });
8564
- var createStyler = (open, close, parent) => {
8565
- let openAll;
8566
- let closeAll;
8567
- if (parent === void 0) {
8568
- openAll = open;
8569
- closeAll = close;
8570
- } else {
8571
- openAll = parent.openAll + open;
8572
- closeAll = close + parent.closeAll;
8573
- }
8574
- return {
8575
- open,
8576
- close,
8577
- openAll,
8578
- closeAll,
8579
- parent
8580
- };
8581
- };
8582
- var createBuilder = (self, _styler, _isEmpty) => {
8583
- const builder = (...arguments_) => {
8584
- if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) return applyStyle(builder, chalkTag(builder, ...arguments_));
8585
- return applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
8586
- };
8587
- Object.setPrototypeOf(builder, proto);
8588
- builder._generator = self;
8589
- builder._styler = _styler;
8590
- builder._isEmpty = _isEmpty;
8591
- return builder;
8592
- };
8593
- var applyStyle = (self, string) => {
8594
- if (self.level <= 0 || !string) return self._isEmpty ? "" : string;
8595
- let styler = self._styler;
8596
- if (styler === void 0) return string;
8597
- const { openAll, closeAll } = styler;
8598
- if (string.indexOf("\x1B") !== -1) while (styler !== void 0) {
8599
- string = stringReplaceAll(string, styler.close, styler.open);
8600
- styler = styler.parent;
8601
- }
8602
- const lfIndex = string.indexOf("\n");
8603
- if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
8604
- return openAll + string + closeAll;
8605
- };
8606
- var template;
8607
- var chalkTag = (chalk, ...strings) => {
8608
- const [firstString] = strings;
8609
- if (!isArray(firstString) || !isArray(firstString.raw)) return strings.join(" ");
8610
- const arguments_ = strings.slice(1);
8611
- const parts = [firstString.raw[0]];
8612
- for (let i = 1; i < firstString.length; i++) parts.push(String(arguments_[i - 1]).replace(/[{}\\]/g, "\\$&"), String(firstString.raw[i]));
8613
- if (template === void 0) template = require_templates();
8614
- return template(chalk, parts.join(""));
8615
- };
8616
- Object.defineProperties(Chalk.prototype, styles);
8617
- var chalk = Chalk();
8618
- chalk.supportsColor = stdoutColor;
8619
- chalk.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
8620
- chalk.stderr.supportsColor = stderrColor;
8621
- module.exports = chalk;
8622
- }));
8623
- require___vite_browser_external();
8624
- require_source();
8625
- var moduleDir = path.dirname(fileURLToPath$1(import.meta.url));
8626
- //#endregion
8627
- //#region src/cli-helpers.ts
6357
+ }
6358
+ /**
6359
+ * Where a package's own manifest lives, or null if it is not installed here.
6360
+ *
6361
+ * `package.json` rather than the package root: a package with an `exports` map
6362
+ * that omits `.` is unresolvable by name even when it is perfectly installed,
6363
+ * which would misreport it as absent.
6364
+ */
6365
+ function resolvePackageManifest(packageName) {
6366
+ const bases = [pathToFileURL(path.join(process.cwd(), "package.json")), pathToFileURL(path.join(moduleDir, "package.json"))];
6367
+ for (const base of bases) try {
6368
+ return createRequire(base).resolve(`${packageName}/package.json`);
6369
+ } catch {}
6370
+ return null;
6371
+ }
6372
+ /**
6373
+ * The binaries a package's own manifest declares, as absolute paths.
6374
+ *
6375
+ * `bin` is a string for a single binary named after the package, or a map.
6376
+ * Both forms appear in the wild and `@ariga/atlas` uses the map.
6377
+ */
6378
+ function declaredBinaries(manifestPath) {
6379
+ let manifest;
6380
+ try {
6381
+ manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
6382
+ } catch {
6383
+ return [];
6384
+ }
6385
+ const dir = path.dirname(manifestPath);
6386
+ if (typeof manifest.bin === "string") return [path.resolve(dir, manifest.bin)];
6387
+ if (manifest.bin && typeof manifest.bin === "object") return Object.values(manifest.bin).filter((target) => typeof target === "string").map((target) => path.resolve(dir, target));
6388
+ return [];
6389
+ }
6390
+ function diagnoseMissingBin(packageName) {
6391
+ const manifestPath = resolvePackageManifest(packageName);
6392
+ if (!manifestPath) return "not-installed";
6393
+ const binaries = declaredBinaries(manifestPath);
6394
+ if (binaries.length === 0) return "build-script-blocked";
6395
+ return binaries.some((file) => fs.existsSync(file)) ? "bin-link-missing" : "build-script-blocked";
6396
+ }
8628
6397
  function resolveLocalBin(binName) {
8629
6398
  let dir = moduleDir;
8630
6399
  while (true) {
@@ -8648,397 +6417,676 @@ function resolveLocalBin(binName) {
8648
6417
  } catch {}
8649
6418
  return null;
8650
6419
  }
8651
- //#endregion
8652
- //#region src/backup/backup-logic.ts
6420
+ async function getTableIncludesFromCollections(allCollections) {
6421
+ const { getTableName, resolveCollectionRelations, relationalCollections } = await import("@rebasepro/common");
6422
+ const { isPostgresCollectionConfig } = await import("@rebasepro/types");
6423
+ const collections = relationalCollections(allCollections);
6424
+ const includes = [];
6425
+ for (const col of collections) {
6426
+ const tableName = getTableName(col);
6427
+ const schema = isPostgresCollectionConfig(col) && col.schema ? col.schema : "public";
6428
+ if (tableName) includes.push(`${schema}.${tableName}`);
6429
+ const resolvedRelations = resolveCollectionRelations(col);
6430
+ for (const relation of Object.values(resolvedRelations)) if (isManyToMany(relation)) {
6431
+ const junctionTableName = relation.through.table;
6432
+ const targetCollection = relation.target();
6433
+ const targetSchema = isPostgresCollectionConfig(targetCollection) && targetCollection.schema ? targetCollection.schema : "public";
6434
+ includes.push(`${targetSchema}.${junctionTableName}`);
6435
+ }
6436
+ }
6437
+ return Array.from(new Set(includes));
6438
+ }
6439
+ async function getTableIncludes(collectionsPath) {
6440
+ return getTableIncludesFromCollections(await loadCollectionsForCli(collectionsPath));
6441
+ }
8653
6442
  /**
8654
- * Pure-ish orchestration for the backup/restore paths, kept free of `execa`
8655
- * and `pg` value imports so it can be unit-tested under jest (the impure
8656
- * edges — spawning processes, opening connections — live in
8657
- * `backup-service.ts`, which is vitest/runtime only).
6443
+ * Load a project's collections the way the Atlas-facing commands need them.
8658
6444
  *
8659
- * The functions here take their side-effecting dependency as an argument
8660
- * (a statement runner, an object deleter) so tests can inject fakes.
6445
+ * Deliberately forgiving a file that fails to import is skipped rather than
6446
+ * fatal because the callers use this to *narrow* what Atlas may touch, and a
6447
+ * hard failure here would block a push over an unrelated broken file. Callers
6448
+ * that cannot tolerate a partial answer (the table excludes, which fail closed)
6449
+ * check the result themselves.
8661
6450
  */
6451
+ /** Paths this process has already complained about. See {@link loadCollectionsForCli}. */
6452
+ var warnedMissingCollectionsPaths = /* @__PURE__ */ new Set();
6453
+ async function loadCollectionsForCli(collectionsPath) {
6454
+ const resolvedPath = path.resolve(collectionsPath);
6455
+ const collections = [];
6456
+ if (!fs.existsSync(resolvedPath) && !warnedMissingCollectionsPaths.has(resolvedPath)) {
6457
+ warnedMissingCollectionsPaths.add(resolvedPath);
6458
+ outWarn(chalk.yellow(` ⚠ Collections path not found: "${collectionsPath}"\n Resolved to: ${resolvedPath}\n (relative to cwd: ${process.cwd()})\n Pass an absolute path, or a path relative to where you run the command.`));
6459
+ }
6460
+ if (fs.existsSync(resolvedPath)) {
6461
+ if (fs.statSync(resolvedPath).isDirectory()) {
6462
+ const files = fs.readdirSync(resolvedPath);
6463
+ for (const file of files) if ((file.endsWith(".ts") || file.endsWith(".js")) && !file.includes(".test.") && !file.endsWith(".d.ts") && file !== "index.ts" && file !== "index.js") try {
6464
+ const module = await import(pathToFileURL(path.join(resolvedPath, file)).href);
6465
+ if (module && module.default) collections.push(module.default);
6466
+ } catch {}
6467
+ }
6468
+ }
6469
+ return collections;
6470
+ }
6471
+ function getDevDatabaseUrl(databaseUrl) {
6472
+ try {
6473
+ const parsed = new URL(databaseUrl);
6474
+ parsed.pathname = `/${parsed.pathname.slice(1)}_dev_diff`;
6475
+ return parsed.toString();
6476
+ } catch {
6477
+ return databaseUrl + "_dev_diff";
6478
+ }
6479
+ }
8662
6480
  /**
8663
- * Replay a `pg_dumpall --globals-only` script one statement at a time,
8664
- * tolerating per-statement failures. On a same-cluster restore the roles
8665
- * usually already exist (`CREATE ROLE` → "already exists") and on a managed
8666
- * provider an `ALTER ROLE <superuser>` may be refused; neither should abort
8667
- * recreation of the roles that *are* missing. Returns how many statements
8668
- * applied vs were skipped.
6481
+ * Create the scratch database Atlas plans against, and say so when we cannot.
8669
6482
  *
8670
- * `runStatement` executes one SQL statement and rejects on error.
6483
+ * Atlas needs a `--dev-url` an empty database it can build the desired state
6484
+ * in — and this makes `<db>_dev_diff` next to the real one. The whole body used
6485
+ * to be wrapped in an empty catch commented "Ignore, let Atlas handle
6486
+ * connection failures", and Atlas's version of handling it is `postgres:
6487
+ * querying system variables: pq: database "app_dev_diff" does not exist
6488
+ * (3D000)` — the symptom, four frames downstream of the cause, with the cause
6489
+ * thrown away.
6490
+ *
6491
+ * The cause is almost always `42501`: `CREATE DATABASE` is a privilege managed
6492
+ * providers do not grant, so this is the first thing a hosted user hits and the
6493
+ * one they can do least with.
6494
+ *
6495
+ * @returns whether the scratch database was created by *this* call — the only
6496
+ * case in which dropping it afterwards is ours to do.
8671
6497
  */
8672
- async function applyGlobalsWith(runStatement, globalsSql, log = () => {}) {
8673
- let applied = 0;
8674
- let skipped = 0;
8675
- for (const statement of splitGlobalsStatements(globalsSql)) try {
8676
- await runStatement(statement);
8677
- applied++;
6498
+ async function ensureDevDatabaseExists(databaseUrl, devDatabaseUrl) {
6499
+ let devDbName = "";
6500
+ try {
6501
+ const { Client } = await import("pg");
6502
+ const parsed = new URL(databaseUrl);
6503
+ devDbName = new URL(devDatabaseUrl).pathname.slice(1);
6504
+ parsed.pathname = "/postgres";
6505
+ const client = new Client({ connectionString: parsed.toString() });
6506
+ await client.connect();
6507
+ try {
6508
+ if ((await client.query("SELECT 1 FROM pg_database WHERE datname = $1", [devDbName])).rowCount === 0) {
6509
+ await client.query(`CREATE DATABASE "${devDbName}"`);
6510
+ out(chalk.gray(` ✓ Created validation database "${devDbName}"`));
6511
+ return true;
6512
+ }
6513
+ } finally {
6514
+ await client.end();
6515
+ }
8678
6516
  } catch (err) {
8679
- skipped++;
8680
- log(` • Skipped global: ${statement.split("\n")[0].slice(0, 80)} (${err instanceof Error ? err.message : String(err)})`);
6517
+ outWarn(describeDevDatabaseFailure(err, devDbName || "<db>_dev_diff"));
8681
6518
  }
8682
- return {
8683
- applied,
8684
- skipped
8685
- };
6519
+ return false;
8686
6520
  }
8687
6521
  /**
8688
- * Delete each pruned dump together with its `.globals.sql` roles sidecar, so
8689
- * pruning never orphans the roles file. The sidecar is best-effort — older
8690
- * backups predate it, so a missing-sidecar failure is swallowed while a
8691
- * failure deleting the dump itself propagates.
6522
+ * What went wrong creating the scratch database, and what to do about it.
8692
6523
  *
8693
- * `deleteObject` removes one key and rejects if it cannot (e.g. not found).
6524
+ * Exported for its test: the `42501` branch is the one that matters and it
6525
+ * cannot be provoked without a non-superuser role.
8694
6526
  */
8695
- async function pruneWith(keys, deleteObject) {
8696
- for (const key of keys) {
8697
- await deleteObject(key);
8698
- try {
8699
- await deleteObject(globalsFileForDump(key));
8700
- } catch {}
8701
- }
6527
+ function describeDevDatabaseFailure(err, devDbName) {
6528
+ const code = err?.code;
6529
+ const message = err instanceof Error ? err.message : String(err);
6530
+ const lines = [chalk.yellow(` ⚠ Could not create the Atlas scratch database "${devDbName}": ${message}`)];
6531
+ if (code === "42501") lines.push(chalk.gray(` Atlas plans every change in a throwaway copy of the schema, and CREATE DATABASE
6532
+ is a privilege most managed providers withhold. Two ways forward:
6533
+ • GRANT the role CREATEDB: ALTER ROLE "<role>" CREATEDB;
6534
+ • or create it once by hand: CREATE DATABASE "${devDbName}";`));
6535
+ else lines.push(chalk.gray(" Atlas will fail next with `database \"" + devDbName + "\" does not exist (3D000)`, which is this."));
6536
+ return lines.join("\n");
8702
6537
  }
8703
6538
  /**
8704
- * Remove a dump artifact abandoned by a failed tool run.
8705
- *
8706
- * `pg_dump` creates its `--file=` target before it finishes connecting, so any
8707
- * failure — a URL libpq rejects, a dropped connection, a full disk — leaves a
8708
- * 0-byte file behind. That corpse is not inert: `rebase db backups list` used
8709
- * to show it as an ordinary entry, and `selectBackupsToPrune` ranks by
8710
- * timestamp alone, so it occupies a protected `keepMinimum` slot and can push
8711
- * a real backup out of retention.
8712
- *
8713
- * Best-effort on purpose: the caller is already throwing, and a failed unlink
8714
- * must not replace the real diagnosis with an ENOENT/EPERM from the cleanup.
6539
+ * Drop the scratch database again, after the command that needed it succeeded.
8715
6540
  *
8716
- * Lives here rather than in `backup-service.ts` for the reason at the top of
8717
- * this file that module's top-level `execa` import makes it unloadable under
8718
- * jest, so anything placed there cannot be unit-tested.
6541
+ * It is a full copy of the schema no rows, but every table, type and index —
6542
+ * and it was left behind per target forever. The only notice anyone got was
6543
+ * `rebase db branch prune` reporting "3 Atlas scratch database(s) left over
6544
+ * from db push", and on a provider that bills per database it is a silent cost.
8719
6545
  *
8720
- * `remove` deletes one file and throws if it cannot; `exists` reports presence.
6546
+ * Deliberately NOT called on the failure path: after a failed push the scratch
6547
+ * database holds the state Atlas was planning against, which is the one thing
6548
+ * worth inspecting.
8721
6549
  */
8722
- function discardPartialDumpWith(exists, remove, file) {
6550
+ async function dropDevDatabase(databaseUrl, devDatabaseUrl) {
8723
6551
  try {
8724
- if (exists(file)) remove(file);
8725
- } catch {}
6552
+ const { Client } = await import("pg");
6553
+ const parsed = new URL(databaseUrl);
6554
+ const devDbName = new URL(devDatabaseUrl).pathname.slice(1);
6555
+ parsed.pathname = "/postgres";
6556
+ const client = new Client({ connectionString: parsed.toString() });
6557
+ await client.connect();
6558
+ try {
6559
+ await client.query(`DROP DATABASE IF EXISTS "${devDbName}"`);
6560
+ out(chalk.gray(` ✓ Removed validation database "${devDbName}"`));
6561
+ } finally {
6562
+ await client.end();
6563
+ }
6564
+ } catch (err) {
6565
+ outWarn(chalk.gray(` ⚠ Could not remove the Atlas scratch database: ${err instanceof Error ? err.message : String(err)}\n \`rebase db branch prune --include-dev-diff\` clears them.`));
6566
+ }
8726
6567
  }
8727
- //#endregion
8728
- //#region src/backup/backup-service.ts
8729
6568
  /**
8730
- * Backup / restore orchestration: thin, well-typed wrappers around
8731
- * `pg_dump` and `pg_restore`, plus binary detection, version pre-flight,
8732
- * and upload/prune against a storage backend.
6569
+ * The generated SQL for the project's `search` blocks, if it has any.
8733
6570
  *
8734
- * The pure argument- and policy-logic lives in `pg-tools.ts` and
8735
- * `retention.ts`; this module is the impure edge (spawns processes, talks
8736
- * to Postgres and storage) and is intentionally kept small.
6571
+ * @param drizzleDir directory holding the generated SQL. Defaults to `drizzle`
6572
+ * under the working directory.
8737
6573
  */
8738
- var backup_service_exports = /* @__PURE__ */ __exportAll({
8739
- BackupToolError: () => BackupToolError,
8740
- applyGlobals: () => applyGlobals,
8741
- createDump: () => createDump,
8742
- detectToolMajor: () => detectToolMajor,
8743
- discardPartialDump: () => discardPartialDump,
8744
- ensureDatabaseExists: () => ensureDatabaseExists,
8745
- getServerVersionMajor: () => getServerVersionMajor,
8746
- listBackups: () => listBackups,
8747
- preflight: () => preflight,
8748
- pruneBackups: () => pruneBackups,
8749
- resolvePgBinary: () => resolvePgBinary,
8750
- restoreDump: () => restoreDump,
8751
- uploadBackup: () => uploadBackup,
8752
- validateDump: () => validateDump
8753
- });
6574
+ function readSearchDdl(drizzleDir = path.resolve(process.cwd(), "drizzle")) {
6575
+ const searchFile = path.join(drizzleDir, "search.sql");
6576
+ if (!fs.existsSync(searchFile)) return "";
6577
+ return fs.readFileSync(searchFile, "utf-8").trim();
6578
+ }
8754
6579
  /**
8755
- * Remove a dump artifact abandoned by a failed tool run. See
8756
- * {@link discardPartialDumpWith} for why this exists and why the logic lives
8757
- * in the execa-free module.
6580
+ * Bring the search column, its index and their helpers up to date.
6581
+ *
6582
+ * Runs *after* Atlas, not before: the statements are `ALTER TABLE ... ADD
6583
+ * COLUMN`, so the table has to exist. Atlas is told to ignore these objects
6584
+ * entirely (`getSearchExcludes`) — it cannot manage them, and left to itself it
6585
+ * would plan a `DROP COLUMN` for every one, since they are absent from the
6586
+ * desired state it was given.
6587
+ *
6588
+ * A no-op when no collection declared `search`. A failure is *not* swallowed:
6589
+ * silently pushing a schema whose search column never appeared is how a
6590
+ * collection ends up with search configured, no error anywhere, and no results.
8758
6591
  */
8759
- function discardPartialDump(file) {
8760
- discardPartialDumpWith((f) => fs.existsSync(f), (f) => fs.unlinkSync(f), file);
8761
- }
8762
- var BackupToolError = class extends Error {
8763
- hint;
8764
- constructor(message, hint) {
8765
- super(message);
8766
- this.hint = hint;
8767
- this.name = "BackupToolError";
8768
- }
8769
- };
8770
- /** Locate `pg_dump` / `pg_restore` / `pg_dumpall`, honouring an env override. */
8771
- function resolvePgBinary(tool, env = process.env) {
8772
- const overrideVar = tool === "pg_dump" ? env.PG_DUMP_PATH : tool === "pg_restore" ? env.PG_RESTORE_PATH : env.PG_DUMPALL_PATH;
8773
- if (overrideVar && fs.existsSync(overrideVar)) return overrideVar;
8774
- return resolveLocalBin(tool);
8775
- }
8776
- /** Run `<bin> --version` and extract the major version. */
8777
- async function detectToolMajor(bin) {
8778
- try {
8779
- const { stdout } = await execa(bin, ["--version"]);
8780
- return parsePgToolMajor(stdout);
8781
- } catch {
8782
- return null;
8783
- }
8784
- }
8785
- /** Query the server for its major version via `server_version_num`. */
8786
- async function getServerVersionMajor(connectionString) {
6592
+ async function applySearchDdl(databaseUrl, drizzleDir = path.resolve(process.cwd(), "drizzle")) {
6593
+ const sql = readSearchDdl(drizzleDir);
6594
+ if (!sql) return;
8787
6595
  const { Client } = await import("pg");
8788
- const client = new Client({ connectionString });
6596
+ const client = new Client({ connectionString: databaseUrl });
8789
6597
  await client.connect();
8790
6598
  try {
8791
- const raw = (await client.query("SHOW server_version_num")).rows?.[0]?.server_version_num;
8792
- return serverVersionNumToMajor(raw);
6599
+ await client.query(sql);
8793
6600
  } finally {
8794
6601
  await client.end();
8795
6602
  }
6603
+ out(chalk.gray(" ✓ Applied full-text search columns and indexes"));
8796
6604
  }
8797
6605
  /**
8798
- * Verify the requested client tool exists and its major version is
8799
- * compatible with the live server. Throws {@link BackupToolError} — with a
8800
- * doctor-style hintwhen the binary is missing.
6606
+ * Glob patterns keeping Atlas away from the search objects.
6607
+ *
6608
+ * Returns an empty list and so changes nothing — for a project with no
6609
+ * `search` block, which is every project that has not opted in.
8801
6610
  */
8802
- async function preflight(tool, connectionString, env = process.env) {
8803
- const bin = resolvePgBinary(tool, env);
8804
- if (!bin) throw new BackupToolError(`Could not find the '${tool}' binary.`, `Install the PostgreSQL client tools (e.g. 'brew install libpq' or 'apt-get install postgresql-client'), or set ${tool === "pg_dump" ? "PG_DUMP_PATH" : "PG_RESTORE_PATH"} to its full path.`);
8805
- const [toolMajor, serverMajor] = await Promise.all([detectToolMajor(bin), getServerVersionMajor(connectionString)]);
8806
- return {
8807
- bin,
8808
- toolMajor,
8809
- serverMajor,
8810
- ...checkToolServerCompatibility(toolMajor, serverMajor)
8811
- };
6611
+ async function getSearchExcludes(collectionsPath) {
6612
+ const { searchExcludePatterns } = await import("./generate-postgres-ddl-logic-CtnpIBVv.js").then((n) => n.o);
6613
+ return searchExcludePatterns(await loadCollectionsForCli(collectionsPath));
8812
6614
  }
8813
6615
  /**
8814
- * Produce a custom-format dump on local disk. When `outDir` is omitted the
8815
- * file is written to the OS temp directory (used by the upload path, which
8816
- * cleans it up afterwards).
6616
+ * The generated SQL for the project's `vector` properties, if it has any.
8817
6617
  *
8818
- * Alongside the `-Fc` dump it writes a `<name>.globals.sql` sidecar via
8819
- * `pg_dumpall --globals-only` so the roles the dump's GRANT/RLS statements
8820
- * depend on can be recreated on restore. Set `includeGlobals: false` to skip
8821
- * it (e.g. when the caller has no privilege to read cluster globals).
6618
+ * @param drizzleDir directory holding the generated SQL. Defaults to `drizzle`
6619
+ * under the working directory.
8822
6620
  */
8823
- async function createDump(opts) {
8824
- const env = opts.env ?? process.env;
8825
- const bin = resolvePgBinary("pg_dump", env);
8826
- if (!bin) throw new BackupToolError("Could not find the 'pg_dump' binary.", "Install the PostgreSQL client tools or set PG_DUMP_PATH.");
8827
- const fileName = opts.fileName ?? buildBackupFilename(opts.dbName);
8828
- const outDir = opts.outDir ?? fs.mkdtempSync(path.join(os.tmpdir(), "rebase-backup-"));
8829
- fs.mkdirSync(outDir, { recursive: true });
8830
- const localFile = path.join(outDir, fileName);
8831
- const args = buildPgDumpArgs({
8832
- connectionString: opts.connectionString,
8833
- outFile: localFile,
8834
- excludeSchemas: opts.excludeSchemas,
8835
- noOwner: opts.noOwner,
8836
- rowSecurity: opts.rowSecurity
8837
- });
8838
- const dumpEnv = { ...env };
8839
- if (opts.rowSecurity) dumpEnv.PGOPTIONS = [env.PGOPTIONS, buildRowSecurityPgOptions(opts.rowSecurity)].filter(Boolean).join(" ");
8840
- try {
8841
- await execa(bin, args, {
8842
- stdio: opts.inheritStdio ? "inherit" : "pipe",
8843
- env: dumpEnv
8844
- });
8845
- } catch (error) {
8846
- discardPartialDump(localFile);
8847
- const diagnosis = diagnoseRowSecurityDumpFailure(error);
8848
- if (!diagnosis) throw error;
8849
- throw new BackupToolError(diagnosis, "Run `rebase db backup --help` for the flag, and read what it says about partial dumps.");
8850
- }
8851
- const result = {
8852
- localFile,
8853
- fileName,
8854
- sizeBytes: fs.existsSync(localFile) ? fs.statSync(localFile).size : 0
8855
- };
8856
- if (opts.includeGlobals !== false) {
8857
- const dumpallBin = resolvePgBinary("pg_dumpall", env);
8858
- if (!dumpallBin) throw new BackupToolError("Could not find the 'pg_dumpall' binary needed to capture cluster roles.", "Install the PostgreSQL client tools or set PG_DUMPALL_PATH. To take a role-incomplete backup anyway, pass includeGlobals: false.");
8859
- const globalsFile = globalsFileForDump(localFile);
8860
- try {
8861
- await execa(dumpallBin, buildPgDumpallGlobalsArgs({
8862
- connectionString: opts.connectionString,
8863
- outFile: globalsFile
8864
- }), {
8865
- stdio: opts.inheritStdio ? "inherit" : "pipe",
8866
- env: { ...env }
8867
- });
8868
- } catch (error) {
8869
- discardPartialDump(globalsFile);
8870
- discardPartialDump(localFile);
8871
- throw error;
8872
- }
8873
- result.globalsFile = globalsFile;
8874
- result.globalsSizeBytes = fs.existsSync(globalsFile) ? fs.statSync(globalsFile).size : 0;
8875
- }
8876
- return result;
6621
+ function readVectorDdl(drizzleDir = path.resolve(process.cwd(), "drizzle")) {
6622
+ const vectorFile = path.join(drizzleDir, "vector.sql");
6623
+ if (!fs.existsSync(vectorFile)) return "";
6624
+ return fs.readFileSync(vectorFile, "utf-8").trim();
8877
6625
  }
8878
6626
  /**
8879
- * Cheap integrity check on a freshly written dump: it must be non-empty and
8880
- * `pg_restore --list` must parse its table of contents without error. Used
8881
- * before pruning older backups so a corrupt-but-exit-0 dump never becomes
8882
- * the reason the last good backup is deleted.
6627
+ * Install pgvector and bring the vector columns and their ANN indexes up to
6628
+ * date.
6629
+ *
6630
+ * Runs *after* Atlas, like {@link applySearchDdl} and for the same reason: the
6631
+ * statements are `ALTER TABLE … ADD COLUMN`, so the table has to exist. Atlas
6632
+ * is told to ignore these objects entirely ({@link getVectorExcludes}) — it
6633
+ * cannot manage a type its dev database is structurally incapable of having,
6634
+ * and left to itself it would plan a `DROP COLUMN` for every one.
6635
+ *
6636
+ * A no-op when no collection declares a `vector` property. A failure is *not*
6637
+ * swallowed: a push that reported success while the embedding column never
6638
+ * appeared is how a project ends up with vector search configured, no error
6639
+ * anywhere, and no results.
8883
6640
  */
8884
- async function validateDump(localFile, env = process.env) {
8885
- if (!fs.existsSync(localFile)) return {
8886
- ok: false,
8887
- reason: `Dump file does not exist: ${localFile}`
8888
- };
8889
- if (fs.statSync(localFile).size === 0) return {
8890
- ok: false,
8891
- reason: "Dump file is empty (0 bytes)."
8892
- };
8893
- const bin = resolvePgBinary("pg_restore", env);
8894
- if (!bin) return {
8895
- ok: false,
8896
- reason: "Could not find 'pg_restore' to verify the dump."
8897
- };
6641
+ async function applyVectorDdl(databaseUrl, drizzleDir = path.resolve(process.cwd(), "drizzle")) {
6642
+ const sql = readVectorDdl(drizzleDir);
6643
+ if (!sql) return;
6644
+ const { vectorExtensionHint } = await import("./vector-index-DkWxm2de.js").then((n) => n.f);
6645
+ const { Client } = await import("pg");
6646
+ const client = new Client({ connectionString: databaseUrl });
6647
+ await client.connect();
8898
6648
  try {
8899
- await execa(bin, buildPgRestoreListArgs(localFile), {
8900
- stdio: "pipe",
8901
- env: { ...env }
8902
- });
8903
- return { ok: true };
6649
+ await client.query(sql);
8904
6650
  } catch (err) {
8905
- return {
8906
- ok: false,
8907
- reason: `pg_restore --list failed: ${err instanceof Error ? err.message : String(err)}`
8908
- };
6651
+ const message = err instanceof Error ? err.message : String(err);
6652
+ const hint = vectorExtensionHint(message);
6653
+ if (!hint) throw err;
6654
+ throw new Error(`${message}${hint}`, { cause: err });
6655
+ } finally {
6656
+ await client.end();
8909
6657
  }
6658
+ out(chalk.gray(" ✓ Applied vector columns and ANN indexes"));
6659
+ }
6660
+ /**
6661
+ * Glob patterns keeping Atlas away from the vector objects.
6662
+ *
6663
+ * Returns an empty list — and so changes nothing — for a project with no
6664
+ * `vector` property, which is every project that has not opted in.
6665
+ */
6666
+ async function getVectorExcludes(collectionsPath) {
6667
+ const { vectorExcludePatterns } = await import("./generate-postgres-ddl-logic-CtnpIBVv.js").then((n) => n.o);
6668
+ return vectorExcludePatterns(await loadCollectionsForCli(collectionsPath));
8910
6669
  }
8911
6670
  /**
8912
- * Replay a `pg_dumpall --globals-only` script to recreate cluster roles
8913
- * before a restore, so the dump's GRANT/RLS statements (which reference
8914
- * `rebase_user` and any owner roles) actually apply. Runs statement by
8915
- * statement and tolerates per-statement failures — on a same-cluster restore
8916
- * the roles usually already exist (`CREATE ROLE` → "already exists"), and on
8917
- * a managed provider an `ALTER ROLE <superuser>` may be refused; neither
8918
- * should abort role recreation. Returns how many statements applied vs were
8919
- * skipped.
6671
+ * Query the live database for every user table/view outside the system
6672
+ * catalogs. Separated from {@link getTableExcludes} so its failure mode can
6673
+ * be handled explicitly (fail closed) and so tests can inject a stub.
6674
+ */
6675
+ /**
6676
+ * Every index Postgres holds on a table Rebase manages, as
6677
+ * `schema.table.index`.
6678
+ *
6679
+ * Constraint-backed indexes are left out: a `PRIMARY KEY` or a `UNIQUE` is a
6680
+ * *constraint* to Atlas, diffed from the constraint declaration, and naming its
6681
+ * index in an exclude would shield the constraint itself.
8920
6682
  */
8921
- async function applyGlobals(connectionString, globalsSql, log = () => {}) {
6683
+ async function queryExistingIndexes(databaseUrl) {
8922
6684
  const { Client } = await import("pg");
8923
- const client = new Client({ connectionString });
6685
+ const client = new Client({ connectionString: databaseUrl });
8924
6686
  await client.connect();
8925
6687
  try {
8926
- return await applyGlobalsWith(async (sql) => {
8927
- await client.query(sql);
8928
- }, globalsSql, log);
6688
+ return (await client.query(`
6689
+ SELECT n.nspname || '.' || t.relname || '.' || i.relname AS full_name
6690
+ FROM pg_index x
6691
+ JOIN pg_class i ON i.oid = x.indexrelid
6692
+ JOIN pg_class t ON t.oid = x.indrelid
6693
+ JOIN pg_namespace n ON n.oid = t.relnamespace
6694
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
6695
+ AND t.relkind IN ('r', 'p')
6696
+ AND NOT EXISTS (
6697
+ SELECT 1 FROM pg_constraint c WHERE c.conindid = i.oid
6698
+ );
6699
+ `)).rows.map((row) => row.full_name);
8929
6700
  } finally {
8930
6701
  await client.end();
8931
6702
  }
8932
6703
  }
8933
6704
  /**
8934
- * Restore a custom-format dump into the database named by
8935
- * `connectionString`. Destructive when `clean` is set (drops objects
8936
- * first). Never called automatically the CLI gates it behind explicit
8937
- * confirmation.
6705
+ * Glob patterns keeping Atlas away from indexes that are not Rebase's.
6706
+ *
6707
+ * The problem this solves is live and predates the `indexes:` block. `db push`
6708
+ * is declarative, so an index on a managed table that is absent from
6709
+ * `schema.sql` is drift — and Atlas plans `DROP INDEX` for it. Verified
6710
+ * against atlas v1.2.3: create one by hand, re-run an unchanged push, and the
6711
+ * plan is a bare drop. `DROP INDEX` is not in `DESTRUCTIVE_PATTERNS`, so the
6712
+ * auto-approved apply took it without asking. Until now the only way to have
6713
+ * an index at all was to write it by hand, which made that the *only* outcome.
8938
6714
  *
8939
- * Runs with `--exit-on-error` by default: a restore that logs-and-continues
8940
- * past a failed GRANT (because a role was missing) reports success with RLS
8941
- * un-enforced. Callers should recreate roles first (see {@link applyGlobals})
8942
- * and only set `exitOnError: false` deliberately.
6715
+ * Ownership rather than a prompt, because once indexes are declarable a drop
6716
+ * is usually correct: removing one from the config should remove it from the
6717
+ * database, quietly. What must never be dropped is an index Rebase never
6718
+ * created a hand-written one, or one an introspected database arrived with.
6719
+ * {@link isRebaseIndexName} is the test, the same arrangement
6720
+ * `isGeneratedPolicyName` uses to let policy reconciliation drop only what it
6721
+ * generated.
6722
+ *
6723
+ * The named-in-the-desired-state check comes first and is what makes removal
6724
+ * work: a declared index that the author has just deleted still matches the
6725
+ * name pattern, is no longer in the plan, and so is *not* excluded — Atlas
6726
+ * drops it, as intended.
6727
+ *
6728
+ * Three-part `schema.table.index`, never two: a two-part pattern reads as a
6729
+ * *table* named `<index>` in a *schema* named `<table>`, matches nothing, and
6730
+ * reports no error — the trap already recorded for the search excludes.
8943
6731
  */
8944
- async function restoreDump(opts) {
8945
- const env = opts.env ?? process.env;
8946
- const bin = resolvePgBinary("pg_restore", env);
8947
- if (!bin) throw new BackupToolError("Could not find the 'pg_restore' binary.", "Install the PostgreSQL client tools or set PG_RESTORE_PATH.");
8948
- await execa(bin, buildPgRestoreArgs({
8949
- connectionString: opts.connectionString,
8950
- inputFile: opts.inputFile,
8951
- clean: opts.clean,
8952
- noOwner: opts.noOwner,
8953
- exitOnError: opts.exitOnError
8954
- }), {
8955
- stdio: opts.inheritStdio ? "inherit" : "pipe",
8956
- env: { ...env }
6732
+ async function getForeignIndexExcludes(databaseUrl, collectionsPath, deps = {}) {
6733
+ const queryIndexes = deps.queryExistingIndexes ?? queryExistingIndexes;
6734
+ const managed = await (deps.getManagedIndexNames ?? managedIndexNames)(collectionsPath);
6735
+ let existing;
6736
+ try {
6737
+ existing = await queryIndexes(databaseUrl);
6738
+ } catch (err) {
6739
+ throw new ExcludeIntrospectionError(`Failed to introspect the database for unmanaged indexes: ${err instanceof Error ? err.message : String(err)}`, err);
6740
+ }
6741
+ return existing.filter((full) => {
6742
+ const indexName = full.slice(full.lastIndexOf(".") + 1);
6743
+ if (managed.has(indexName)) return false;
6744
+ return !isRebaseIndexName(indexName);
8957
6745
  });
8958
6746
  }
8959
6747
  /**
8960
- * Create a database (if absent) by connecting to the maintenance
8961
- * `postgres` database. Used by `restore --create-db`.
6748
+ * The index names the current collections would create search, vector and
6749
+ * declared alike. Anything Atlas would emit is by definition not foreign.
8962
6750
  */
8963
- async function ensureDatabaseExists(adminConnectionString, dbName) {
6751
+ async function managedIndexNames(collectionsPath) {
6752
+ const collections = await loadCollectionsForCli(collectionsPath);
6753
+ const { resolveColumnName, searchExcludePatterns, vectorExcludePatterns } = await import("./generate-postgres-ddl-logic-CtnpIBVv.js").then((n) => n.o);
6754
+ const { buildCollectionIndexPlan } = await import("./collection-index-BHgT_TKd.js").then((n) => n.a);
6755
+ const names = new Set(buildCollectionIndexPlan(collections, resolveColumnName).map((spec) => spec.indexName));
6756
+ for (const pattern of [...searchExcludePatterns(collections), ...vectorExcludePatterns(collections)]) names.add(pattern.slice(pattern.lastIndexOf(".") + 1));
6757
+ return names;
6758
+ }
6759
+ async function queryExistingTables(databaseUrl) {
8964
6760
  const { Client } = await import("pg");
8965
- const parsed = new URL(adminConnectionString);
8966
- parsed.pathname = "/postgres";
8967
- const client = new Client({ connectionString: parsed.toString() });
6761
+ const client = new Client({ connectionString: databaseUrl });
8968
6762
  await client.connect();
8969
6763
  try {
8970
- const existing = await client.query("SELECT 1 FROM pg_database WHERE datname = $1", [dbName]);
8971
- if (existing.rowCount && existing.rowCount > 0) return false;
8972
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(dbName)) throw new BackupToolError(`Invalid database name: "${dbName}"`);
8973
- await client.query(`CREATE DATABASE "${dbName}"`);
8974
- return true;
6764
+ return (await client.query(`
6765
+ SELECT table_schema || '.' || table_name AS full_name
6766
+ FROM information_schema.tables
6767
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
6768
+ AND table_type IN ('BASE TABLE', 'VIEW');
6769
+ `)).rows.map((row) => row.full_name);
8975
6770
  } finally {
8976
6771
  await client.end();
8977
6772
  }
8978
6773
  }
8979
6774
  /**
8980
- * Upload a local dump to object storage under the destination's prefix.
8981
- * Backups may contain secrets/PII, so the object is written with a
8982
- * private/octet-stream content type; bucket-level ACLs must stay private.
6775
+ * Raised when the exclude list could not be built. `db push` MUST abort on
6776
+ * this rather than continue: the exclude list is the only thing shielding
6777
+ * non-collection (user/system) tables from the auto-approved declarative
6778
+ * apply. A partial list — the old fail-open behaviour — meant a transient
6779
+ * introspection hiccup dropped every table not present in `schema.sql`.
8983
6780
  */
8984
- async function uploadBackup(storage, localFile, dest) {
8985
- const fileName = path.basename(localFile);
8986
- const key = joinStorageKey(dest.prefix, fileName);
8987
- const buffer = fs.readFileSync(localFile);
8988
- const file = new File([buffer], fileName, { type: "application/octet-stream" });
8989
- return {
8990
- key,
8991
- storageUrl: (await storage.putObject({
8992
- file,
8993
- key,
8994
- bucket: dest.bucket,
8995
- metadata: { "rebase-backup": "1" }
8996
- })).storageUrl
8997
- };
8998
- }
6781
+ var ExcludeIntrospectionError = class extends Error {
6782
+ cause;
6783
+ constructor(message, cause) {
6784
+ super(message);
6785
+ this.cause = cause;
6786
+ this.name = "ExcludeIntrospectionError";
6787
+ }
6788
+ };
8999
6789
  /**
9000
- * List existing backups at a destination. For local destinations reads the
9001
- * directory; for object storage lists the prefix via the controller.
6790
+ * Build the `--exclude` list that protects tables Rebase doesn't manage from
6791
+ * the declarative apply. Anything not backing a collection (or its M2M
6792
+ * junctions) is excluded so Atlas never drops it.
6793
+ *
6794
+ * Fails **closed**: if the database can't be introspected we cannot know
6795
+ * which tables to protect, so we throw {@link ExcludeIntrospectionError}
6796
+ * instead of returning a near-empty list and letting the caller drop
6797
+ * everything.
6798
+ *
6799
+ * `deps` is injectable for tests; production uses the real pg-backed queries.
9002
6800
  */
9003
- async function listBackups(dest, storage) {
9004
- if (dest.kind === "local") {
9005
- if (!fs.existsSync(dest.path)) return [];
9006
- const dir = fs.statSync(dest.path).isDirectory() ? dest.path : path.dirname(dest.path);
9007
- return fs.readdirSync(dir).filter((f) => f.endsWith(".dump")).map((f) => {
9008
- const full = path.join(dir, f);
9009
- const stats = fs.statSync(full);
9010
- return {
9011
- key: full,
9012
- createdAt: parseBackupTimestamp(f) ?? stats.mtime,
9013
- sizeBytes: stats.size
9014
- };
9015
- }).sort((a, b) => (b.createdAt?.getTime() ?? 0) - (a.createdAt?.getTime() ?? 0));
9016
- }
9017
- if (!storage) throw new BackupToolError(`Listing ${dest.kind} backups requires a configured storage backend.`);
9018
- return (await storage.listObjects(dest.prefix ? `${dest.prefix}/` : "", {
9019
- bucket: dest.bucket,
9020
- maxResults: 1e3
9021
- })).items.map((item) => item.fullPath).filter((key) => key.endsWith(".dump")).map((key) => ({
9022
- key,
9023
- createdAt: parseBackupTimestamp(key) ?? void 0
9024
- })).sort((a, b) => (b.createdAt?.getTime() ?? 0) - (a.createdAt?.getTime() ?? 0));
6801
+ async function getTableExcludes(databaseUrl, collectionsPath, deps = {}) {
6802
+ const getIncludes = deps.getIncludes ?? getTableIncludes;
6803
+ const queryTables = deps.queryExistingTables ?? queryExistingTables;
6804
+ const includes = await getIncludes(collectionsPath);
6805
+ const excludes = [
6806
+ "atlas_schema_revisions.*",
6807
+ "auth",
6808
+ "auth.*",
6809
+ "rebase",
6810
+ "rebase.*"
6811
+ ];
6812
+ let existingTables;
6813
+ try {
6814
+ existingTables = await queryTables(databaseUrl);
6815
+ } catch (err) {
6816
+ throw new ExcludeIntrospectionError(`Failed to introspect the database for unmapped tables: ${err instanceof Error ? err.message : String(err)}`, err);
6817
+ }
6818
+ for (const table of existingTables) if (!includes.includes(table)) excludes.push(table);
6819
+ return excludes;
9025
6820
  }
9026
6821
  /**
9027
- * Apply a retention policy to a destination, deleting the backups selected
9028
- * by {@link selectBackupsToPrune}. Returns the keys that were removed.
6822
+ * Ask a yes/no question on an interactive terminal.
6823
+ *
6824
+ * The `isTTY` guard is the contract, not an optimisation: non-interactive
6825
+ * shells (CI, pipes, agents) can never answer, and `readline` on a
6826
+ * non-TTY stdin resolves with whatever the pipe happens to contain — or never
6827
+ * resolves at all. Returning false there is what makes an unattended
6828
+ * `db push` abort instead of auto-confirming a destructive change. Callers
6829
+ * should already have gone through {@link decidePushSafety}, which decides
6830
+ * whether interactive confirmation is even possible; this is the backstop.
6831
+ *
6832
+ * Lives here rather than in cli.ts so it is reachable from a test — cli.ts uses
6833
+ * `import.meta` and cannot be imported by the jest runner.
9029
6834
  */
9030
- async function pruneBackups(dest, options, storage) {
9031
- const toDelete = selectBackupsToPrune(await listBackups(dest, storage), options);
9032
- await pruneWith(toDelete, dest.kind === "local" ? async (key) => {
9033
- if (!fs.existsSync(key)) throw new Error(`not found: ${key}`);
9034
- fs.unlinkSync(key);
9035
- } : async (key) => {
9036
- if (!storage) throw new BackupToolError("Storage backend required to prune object backups.");
9037
- await storage.deleteObject(key, dest.bucket);
6835
+ async function promptConfirm(question) {
6836
+ if (!process.stdin.isTTY) return false;
6837
+ const rl = import___vite_browser_external.default.createInterface({
6838
+ input: process.stdin,
6839
+ output: process.stdout
9038
6840
  });
9039
- return toDelete;
6841
+ try {
6842
+ const answer = await new Promise((resolve) => rl.question(question, resolve));
6843
+ return /^y(es)?$/i.test(answer.trim());
6844
+ } finally {
6845
+ rl.close();
6846
+ }
6847
+ }
6848
+ //#endregion
6849
+ //#region src/schema/rls-bootstrap-sql.ts
6850
+ var rls_bootstrap_sql_exports = /* @__PURE__ */ __exportAll({
6851
+ DROP_LEGACY_AUTH_SCHEMA_SQL: () => DROP_LEGACY_AUTH_SCHEMA_SQL,
6852
+ LEGACY_RLS_DEPENDENTS_SQL: () => LEGACY_RLS_DEPENDENTS_SQL,
6853
+ LEGACY_RLS_FUNCTION_DEPENDENTS_SQL: () => LEGACY_RLS_FUNCTION_DEPENDENTS_SQL,
6854
+ RLS_BOOTSTRAP_SQL: () => RLS_BOOTSTRAP_SQL,
6855
+ RLS_BOOTSTRAP_STATEMENTS: () => RLS_BOOTSTRAP_STATEMENTS,
6856
+ dropLegacyAuthSchema: () => dropLegacyAuthSchema
6857
+ });
6858
+ /**
6859
+ * Canonical SQL bootstrap for the RLS helper functions.
6860
+ *
6861
+ * Generated RLS policies reference `rebase.uid()` / `rebase.roles()` /
6862
+ * `rebase.jwt()`, so any SQL stream that can contain policies must be
6863
+ * self-contained: it has to (re)create these helpers first. This matters for
6864
+ * the migration directory in particular — Atlas replays migrations against a
6865
+ * clean dev database where no out-of-band bootstrap has ever run, so a
6866
+ * migration carrying policies without this preamble fails with
6867
+ * "function rebase.uid() does not exist".
6868
+ *
6869
+ * Idempotent (`IF NOT EXISTS` / `OR REPLACE`) so it can be prepended to every
6870
+ * policies block and re-applied freely. The runtime boot path
6871
+ * (`auth/ensure-tables.ts`) creates the same functions under an advisory lock
6872
+ * for HMR-safety; keep the definitions in sync.
6873
+ *
6874
+ * ## Creating the `rebase` schema here is now safe, and required
6875
+ *
6876
+ * It deliberately did not, once. These functions lived in a schema called
6877
+ * `auth`, and the note here read: creating `rebase` would leak it into Atlas's
6878
+ * replayed migration state, and — absent from the desired `schema.sql` — Atlas
6879
+ * would then plan `DROP SCHEMA "rebase" CASCADE`, taking the auth tables with
6880
+ * it. That reasoning still holds; what changed is the second half of it. The
6881
+ * DDL generator now emits `CREATE SCHEMA IF NOT EXISTS "rebase"`
6882
+ * unconditionally, so the schema is always in the desired state and the diff is
6883
+ * empty. (It used to appear only when some collection happened to declare
6884
+ * `schema: "rebase"` — true for the scaffold's users collection, and not a
6885
+ * property anything guaranteed.) `db push` additionally excludes the whole
6886
+ * schema from the declarative apply.
6887
+ *
6888
+ * See `@rebasepro/types`' `rls-functions` for why the functions moved out of
6889
+ * `auth` at all: the short version is that the name was Supabase's, and
6890
+ * `CREATE OR REPLACE FUNCTION auth.uid() RETURNS text` cannot be applied over
6891
+ * Supabase's `RETURNS uuid` — Postgres refuses, and the refusal used to be
6892
+ * swallowed.
6893
+ */
6894
+ /**
6895
+ * The bootstrap as individual statements.
6896
+ *
6897
+ * Kept as an array because the two consumers need different shapes and only one
6898
+ * of them can take a multi-command string: the migration preamble is written to
6899
+ * a file and replayed by Atlas, but the boot path runs through drizzle, whose
6900
+ * node-postgres handle speaks the extended query protocol and rejects more than
6901
+ * one command per call. Splitting a joined string back apart on `$$;` would be
6902
+ * a parser for a problem that does not need one.
6903
+ */
6904
+ var RLS_BOOTSTRAP_STATEMENTS = [
6905
+ `CREATE SCHEMA IF NOT EXISTS ${REBASE_SCHEMA}`,
6906
+ `CREATE OR REPLACE FUNCTION ${REBASE_SCHEMA}.uid() RETURNS text AS $$
6907
+ SELECT COALESCE(
6908
+ NULLIF(current_setting('app.uid', true), ''),
6909
+ NULLIF(current_setting('app.user_id', true), '')
6910
+ );
6911
+ $$ LANGUAGE sql STABLE`,
6912
+ `CREATE OR REPLACE FUNCTION ${REBASE_SCHEMA}.jwt() RETURNS jsonb AS $$
6913
+ SELECT COALESCE(
6914
+ NULLIF(current_setting('app.jwt', true), ''),
6915
+ '{}'
6916
+ )::jsonb;
6917
+ $$ LANGUAGE sql STABLE`,
6918
+ `CREATE OR REPLACE FUNCTION ${REBASE_SCHEMA}.roles() RETURNS text AS $$
6919
+ SELECT COALESCE(NULLIF(current_setting('app.user_roles', true), ''), '');
6920
+ $$ LANGUAGE sql STABLE`,
6921
+ `CREATE OR REPLACE FUNCTION ${REBASE_SCHEMA}.is_anonymous() RETURNS boolean AS $$
6922
+ SELECT COALESCE(NULLIF(current_setting('app.is_anonymous', true), ''), 'false')::boolean;
6923
+ $$ LANGUAGE sql STABLE`
6924
+ ];
6925
+ /** The same statements as one script, for migration files and raw clients. */
6926
+ 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";
6927
+ /**
6928
+ * Removes the pre-1.0 `auth` schema, but only when Rebase is what put it there.
6929
+ *
6930
+ * ## Why this is safe against a Supabase database
6931
+ *
6932
+ * Two independent guards, and both have to pass:
6933
+ *
6934
+ * 1. **Each function is identified before it is dropped.** Ours returns `text`
6935
+ * and reads the `app.uid` GUC; Supabase's returns `uuid` and reads
6936
+ * `request.jwt.claims`. Nothing is dropped on a signature we did not write,
6937
+ * so a Supabase database — where our `CREATE OR REPLACE` could never have
6938
+ * succeeded in the first place, Postgres refusing to change a return type —
6939
+ * matches nothing and this is a no-op.
6940
+ * 2. **`DROP SCHEMA … RESTRICT`**, never CASCADE. If anything else at all still
6941
+ * lives in `auth` (Supabase's `users` table, its other helpers), the drop
6942
+ * fails and the schema stays. CASCADE here would be unrecoverable.
6943
+ *
6944
+ * ## Why it cannot run too early
6945
+ *
6946
+ * Postgres records a dependency from every RLS policy to the functions its body
6947
+ * calls, so `DROP FUNCTION auth.uid()` fails for as long as a single policy
6948
+ * still references it. That is the interlock, and it is load-bearing: the drop
6949
+ * can only succeed once every policy has been recompiled to \`rebase.uid()\`.
6950
+ * Callers therefore run this *after* applying policies, and treat a failure as
6951
+ * "not yet — try again next boot" rather than as an error.
6952
+ */
6953
+ var DROP_LEGACY_AUTH_SCHEMA_SQL = `
6954
+ DO $rebase_drop_legacy$
6955
+ DECLARE
6956
+ dropped_any boolean := false;
6957
+ BEGIN
6958
+ -- Each function is matched on its own result type and body, so a schema
6959
+ -- that merely shares the name keeps everything it has.
6960
+ IF EXISTS (
6961
+ SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6962
+ WHERE n.nspname = 'auth' AND p.proname = 'uid'
6963
+ AND pg_get_function_result(p.oid) = 'text'
6964
+ AND p.prosrc LIKE '%app.uid%'
6965
+ ) THEN
6966
+ DROP FUNCTION auth.uid();
6967
+ dropped_any := true;
6968
+ END IF;
6969
+
6970
+ IF EXISTS (
6971
+ SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6972
+ WHERE n.nspname = 'auth' AND p.proname = 'jwt'
6973
+ AND pg_get_function_result(p.oid) = 'jsonb'
6974
+ AND p.prosrc LIKE '%app.jwt%'
6975
+ ) THEN
6976
+ DROP FUNCTION auth.jwt();
6977
+ dropped_any := true;
6978
+ END IF;
6979
+
6980
+ IF EXISTS (
6981
+ SELECT 1 FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
6982
+ WHERE n.nspname = 'auth' AND p.proname = 'roles'
6983
+ AND pg_get_function_result(p.oid) = 'text'
6984
+ AND p.prosrc LIKE '%app.user_roles%'
6985
+ ) THEN
6986
+ DROP FUNCTION auth.roles();
6987
+ dropped_any := true;
6988
+ END IF;
6989
+
6990
+ -- RESTRICT: only an empty schema goes. Anything else in there — including a
6991
+ -- Supabase installation left untouched above — keeps it.
6992
+ IF dropped_any THEN
6993
+ BEGIN
6994
+ EXECUTE 'DROP SCHEMA auth RESTRICT';
6995
+ EXCEPTION WHEN OTHERS THEN
6996
+ NULL;
6997
+ END;
6998
+ END IF;
6999
+ END
7000
+ $rebase_drop_legacy$;
7001
+ `;
7002
+ /**
7003
+ * Policies whose body still calls `auth.uid()` / `auth.roles()` / `auth.jwt()`.
7004
+ *
7005
+ * Postgres will not drop a function a policy depends on, so this is exactly the
7006
+ * set standing between a database and losing the legacy schema. Rebase's own
7007
+ * policies leave the list on the next push or boot, when they are recompiled —
7008
+ * anything still here afterwards is hand-written, will never be recompiled by
7009
+ * anybody, and is the reason the drop keeps being skipped. Silence there would
7010
+ * leave an operator staring at a schema the release notes said would go.
7011
+ */
7012
+ var LEGACY_RLS_DEPENDENTS_SQL = `
7013
+ SELECT n.nspname AS schema, c.relname AS "table", p.polname AS policy
7014
+ FROM pg_policy p
7015
+ JOIN pg_class c ON c.oid = p.polrelid
7016
+ JOIN pg_namespace n ON n.oid = c.relnamespace
7017
+ WHERE pg_get_expr(p.polqual, p.polrelid) ~* '\\m${LEGACY_RLS_SCHEMA}\\.(uid|jwt|roles)\\s*\\('
7018
+ OR pg_get_expr(p.polwithcheck, p.polrelid) ~* '\\m${LEGACY_RLS_SCHEMA}\\.(uid|jwt|roles)\\s*\\('
7019
+ ORDER BY 1, 2, 3
7020
+ `;
7021
+ /**
7022
+ * Functions whose body calls `auth.uid()` / `auth.roles()` / `auth.jwt()`.
7023
+ *
7024
+ * This is the half `DROP FUNCTION ... RESTRICT` cannot see, and the reason it
7025
+ * needs its own query. Postgres records a dependency for a *policy* that calls a
7026
+ * function, which is why the drop is safe against the policies above — but a
7027
+ * `LANGUAGE sql` function whose body is a **string literal** is not parsed when
7028
+ * it is created, so nothing is recorded and `RESTRICT` has nothing to refuse on.
7029
+ * The drop succeeds and the caller is left pointing at a function that no longer
7030
+ * exists, which fails at *query* time rather than at boot.
7031
+ *
7032
+ * A downstream project building on these helpers is not hypothetical: the Rebase
7033
+ * control plane defines `auth.is_org_member(uuid)` and `auth.is_org_admin(uuid)`
7034
+ * in this very schema, each calling `auth.uid()` in a string body, and eleven of
7035
+ * its row-level-security policies go through them. Every one of those would have
7036
+ * started failing the first time a recompile left no policy referencing
7037
+ * `auth.uid()` directly — the drop's own precondition.
7038
+ *
7039
+ * Matching on the body text is the only option available, and it is deliberately
7040
+ * broad: a false positive costs a schema that stays one release longer and says
7041
+ * why, while a false negative costs somebody their policies.
7042
+ */
7043
+ var LEGACY_RLS_FUNCTION_DEPENDENTS_SQL = `
7044
+ SELECT n.nspname AS schema, p.proname AS function
7045
+ FROM pg_proc p
7046
+ JOIN pg_namespace n ON n.oid = p.pronamespace
7047
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
7048
+ AND NOT (n.nspname = '${LEGACY_RLS_SCHEMA}' AND p.proname IN ('uid', 'jwt', 'roles'))
7049
+ AND p.prosrc ~* '\\m${LEGACY_RLS_SCHEMA}\\.(uid|jwt|roles)\\s*\\('
7050
+ ORDER BY 1, 2
7051
+ `;
7052
+ /**
7053
+ * Retire the pre-1.0 `auth` schema, reporting what is holding it back.
7054
+ *
7055
+ * The shared implementation behind the CLI's post-push step and the runtime's
7056
+ * post-policy step. Both used to just fire {@link DROP_LEGACY_AUTH_SCHEMA_SQL}
7057
+ * and swallow whatever came back, which is right for the ordinary case — a
7058
+ * table not recompiled *yet* — and wrong for the one that never resolves: a
7059
+ * hand-written policy nothing will ever rewrite. Then the schema stays forever
7060
+ * and nothing ever says why.
7061
+ */
7062
+ async function dropLegacyAuthSchema(run, report) {
7063
+ let blockers;
7064
+ try {
7065
+ blockers = await run(LEGACY_RLS_DEPENDENTS_SQL);
7066
+ } catch {
7067
+ return;
7068
+ }
7069
+ if (blockers.length > 0) {
7070
+ report.warn(`The pre-1.0 \`${LEGACY_RLS_SCHEMA}\` schema cannot be removed yet: ${blockers.length} ${blockers.length === 1 ? "policy still calls" : "policies still call"} \`${LEGACY_RLS_SCHEMA}.uid()\` and friends, and Postgres will not drop a function a policy depends on. Rebase's own policies are rewritten automatically — anything listed here is hand-written SQL that has to be updated to \`${REBASE_SCHEMA}.uid()\` by hand, after which the schema goes on its own:\n` + blockers.map((b) => ` • ${b.schema}.${b.table} → "${b.policy}"`).join("\n"));
7071
+ return;
7072
+ }
7073
+ let borrowers;
7074
+ try {
7075
+ borrowers = await run(LEGACY_RLS_FUNCTION_DEPENDENTS_SQL);
7076
+ } catch {
7077
+ return;
7078
+ }
7079
+ if (borrowers.length > 0) {
7080
+ 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"));
7081
+ return;
7082
+ }
7083
+ try {
7084
+ await run(DROP_LEGACY_AUTH_SCHEMA_SQL);
7085
+ } catch (err) {
7086
+ report.info(`Left the \`${LEGACY_RLS_SCHEMA}\` schema in place: ` + (err instanceof Error ? err.message : String(err)));
7087
+ }
9040
7088
  }
9041
7089
  //#endregion
9042
- export { parseDbNameFromUrl as A, buildRowSecurityPgOptions as C, joinStorageKey as D, globalsFileForDump as E, withDatabaseName as F, resolveConnectionString as M, serverVersionNumToMajor as N, parseBackupDestination as O, splitGlobalsStatements as P, buildPgRestoreListArgs as S, diagnoseRowSecurityDumpFailure as T, selectBackupsToPrune as _, detectToolMajor as a, buildPgDumpallGlobalsArgs as b, getServerVersionMajor as c, pruneBackups as d, resolvePgBinary as f, require_source as g, validateDump as h, createDump as i, parsePgToolMajor as j, parseBackupTimestamp as k, listBackups as l, uploadBackup as m, applyGlobals as n, discardPartialDump as o, restoreDump as p, backup_service_exports as r, ensureDatabaseExists as s, BackupToolError as t, preflight as u, buildBackupFilename as v, checkToolServerCompatibility as w, buildPgRestoreArgs as x, buildPgDumpArgs as y };
7090
+ export { resolveLocalBin as C, readVectorDdl as S, forLibpq as T, getSearchExcludes as _, ExcludeIntrospectionError as a, promptConfirm as b, describeBuildScriptRemedy as c, detectProjectPackageManager as d, diagnoseMissingBin as f, getForeignIndexExcludes as g, getDevDatabaseUrl as h, rls_bootstrap_sql_exports as i, describeDevAddCommand as l, ensureDevDatabaseExists as m, RLS_BOOTSTRAP_STATEMENTS as n, applySearchDdl as o, dropDevDatabase as p, dropLegacyAuthSchema as r, applyVectorDdl as s, RLS_BOOTSTRAP_SQL as t, describeReinstallCommand as u, getTableExcludes as v, execa as w, readSearchDdl as x, getVectorExcludes as y };
9043
7091
 
9044
- //# sourceMappingURL=backup-service-DCk7KhhL.js.map
7092
+ //# sourceMappingURL=rls-bootstrap-sql-DLDnUjtx.js.map