@devdogsuga/devtools 0.1.51-next.541 → 0.1.51-next.545

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.
@@ -1,10 +1,234 @@
1
- import { o as noteRan, r as findRepoRoot, t as RepoNotFoundError, u as cliName } from "./root-CsocfxnK.js";
1
+ import { n as execSync, r as spawnProcess, t as exec } from "./spawn-BvLQzc_K.js";
2
+ import { r as findRepoRoot, t as RepoNotFoundError } from "./root-PA8K5G2d.js";
3
+ import { c as cliName, r as noteRan } from "./failure-log-MSdCgvLc.js";
2
4
  import { createRequire } from "node:module";
3
5
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
6
  import { dirname, join } from "node:path";
5
- import { execFile, execFileSync, spawn } from "node:child_process";
6
- import { promisify } from "node:util";
7
7
  import { pathToFileURL } from "node:url";
8
+ /** The directory (relative to a Backstage root) holding the DevDogsUGA checkout. */
9
+ const DEVDOGSUGA_LINK = "devdogsuga";
10
+ var DevdogsugaMissingError = class extends Error {
11
+ constructor(path) {
12
+ super(`The DevDogsUGA checkout is missing at ${path}. Run \`pnpm devdogsuga\` (links the sibling clone, or \$DEVDOGSUGA_DIR) or \`pnpm install\` in the Backstage root first.`);
13
+ this.name = "DevdogsugaMissingError";
14
+ }
15
+ };
16
+ /** The kind of repo `dir` is the root of, by its `package.json` name; null if neither. */
17
+ function repoKindOf(dir) {
18
+ try {
19
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
20
+ if (pkg.name === "devdogs-monorepo") return "devdogsuga";
21
+ if (pkg.name === "backstage") return "backstage";
22
+ } catch {}
23
+ return null;
24
+ }
25
+ function isDir(path) {
26
+ try {
27
+ return statSync(path).isDirectory();
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+ /**
33
+ * The layout of the repo rooted at `root`. Pure: nothing is memoized, so tests
34
+ * can build fixtures freely. An unrecognised package name is treated as
35
+ * DevDogsUGA (the contract fixtures and every pre-Backstage caller).
36
+ */
37
+ function layoutAt(root) {
38
+ const kind = repoKindOf(root) === "backstage" ? "backstage" : "devdogsuga";
39
+ const sibling = join(root, DEVDOGSUGA_LINK);
40
+ const hasDevdogsuga = kind === "devdogsuga" || isDir(sibling);
41
+ const devdogsugaRoot = kind === "devdogsuga" ? root : sibling;
42
+ const appsDirs = [join(root, "apps")];
43
+ if (kind === "backstage" && hasDevdogsuga) appsDirs.push(join(devdogsugaRoot, "apps"));
44
+ return {
45
+ kind,
46
+ root,
47
+ get devdogsugaRoot() {
48
+ if (!hasDevdogsuga) throw new DevdogsugaMissingError(sibling);
49
+ return devdogsugaRoot;
50
+ },
51
+ ...kind === "backstage" ? { backstageRoot: root } : {},
52
+ hasDevdogsuga,
53
+ appsDirs: appsDirs.filter(isDir),
54
+ envMirrors: kind === "backstage" && hasDevdogsuga ? [devdogsugaRoot] : []
55
+ };
56
+ }
57
+ /** `layout.devdogsugaRoot`, or null instead of a throw when the checkout is missing. */
58
+ function devdogsugaRootOrNull(layout) {
59
+ return layout.hasDevdogsuga ? layout.devdogsugaRoot : null;
60
+ }
61
+ let cached;
62
+ let cachedFor;
63
+ /** The layout of the repo the process is in (`findRepoRoot()`), memoized per root. */
64
+ function resolveLayout() {
65
+ const root = findRepoRoot();
66
+ if (cached === void 0 || cachedFor !== root) {
67
+ cached = layoutAt(root);
68
+ cachedFor = root;
69
+ }
70
+ return cached;
71
+ }
72
+ /** Every directory under `appsDirs` (one app each), de-duplicated by name, sorted by name. */
73
+ function listApps(layout = resolveLayout()) {
74
+ const seen = /* @__PURE__ */ new Map();
75
+ for (const parent of layout.appsDirs) for (const entry of readdirSync(parent, { withFileTypes: true })) {
76
+ if (!entry.isDirectory()) continue;
77
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
78
+ if (!seen.has(entry.name)) seen.set(entry.name, {
79
+ name: entry.name,
80
+ dir: join(parent, entry.name)
81
+ });
82
+ }
83
+ return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
84
+ }
85
+ /** The directory of the app called `name`, or undefined when no repo has it. */
86
+ function findApp(name, layout = resolveLayout()) {
87
+ return listApps(layout).find((app) => app.name === name)?.dir;
88
+ }
89
+ /**
90
+ * Resolves a workspace-relative path such as `workers.json`'s
91
+ * `apps/schedule-builder` to a directory: the repo you are in first, then
92
+ * DevDogsUGA's. When neither has it the first candidate is returned, so
93
+ * callers get an ordinary ENOENT naming the path rather than a second error.
94
+ */
95
+ function resolveAppPath(relative, layout = resolveLayout()) {
96
+ const first = join(layout.root, relative);
97
+ if (existsSync(first)) return first;
98
+ if (layout.kind === "backstage" && layout.hasDevdogsuga) {
99
+ const second = join(layout.devdogsugaRoot, relative);
100
+ if (existsSync(second)) return second;
101
+ }
102
+ return first;
103
+ }
104
+ /**
105
+ * The pnpm workspace root holding the app called `name`: where
106
+ * `pnpm --filter <name>` has to run. DevDogsUGA's root for its apps seen from a
107
+ * Backstage checkout, `layout.root` otherwise.
108
+ */
109
+ function appWorkspaceRoot(name, layout = resolveLayout()) {
110
+ const dir = findApp(name, layout);
111
+ return dir === void 0 ? layout.root : dirname(dirname(dir));
112
+ }
113
+ //#endregion
114
+ //#region ../cli-core/src/repo/supabase-project.ts
115
+ /**
116
+ * This repo's Supabase project id — read from `supabase/config.toml` — and
117
+ * the container-name conventions the Supabase CLI derives from it.
118
+ *
119
+ * Shared by `environment.ts`'s adaptive-menu probe (does a stack answer for
120
+ * THIS project?) and the foreign-stack detection in `db/generated-env.ts`
121
+ * and `stack.ts` (does a DIFFERENT project's stack hold the shared ports? —
122
+ * the case where `supabase status -o env` fails not because nothing is
123
+ * running, but because what is running on 127.0.0.1:54321 belongs to
124
+ * another workspace, or to this same repo before/after a `project_id`
125
+ * rename). One project-id reader and one container-name parser, so both
126
+ * questions agree on what "this project" means.
127
+ */
128
+ /**
129
+ * Reads `project_id` out of `<repoRoot>/supabase/config.toml`, or `null`
130
+ * when the file is missing or unparsable.
131
+ *
132
+ * Regex, not a TOML parser: it is one line, the shape has been stable
133
+ * across every CLI version this repo has seen, and a parser on a path some
134
+ * callers pay before their first real subprocess is a cost that stays
135
+ * invisible until it is why the tool feels slow.
136
+ */
137
+ function readProjectId(repoRoot) {
138
+ try {
139
+ const path = join(repoRoot, "supabase", "config.toml");
140
+ return /^\s*project_id\s*=\s*"([^"]+)"/m.exec(readFileSync(path, "utf8"))?.[1] ?? null;
141
+ } catch {
142
+ return null;
143
+ }
144
+ }
145
+ /**
146
+ * The Supabase CLI's container name prefix for a project id, or the bare
147
+ * `supabase_db_` fallback when the id could not be read.
148
+ *
149
+ * Falling back to the bare prefix means a machine whose `config.toml`
150
+ * cannot be read still detects *a* stack, at the cost of over-matching a
151
+ * differently-named project — deliberate, and unchanged from this
152
+ * function's original home in `environment.ts`: over-matching offers
153
+ * `stop`/a foreign-stack hint for a stack that turns out to be this
154
+ * project's own, which is harmless to see and decline, while
155
+ * under-matching hides a real signal entirely.
156
+ */
157
+ function containerPrefix(projectId) {
158
+ return projectId ? `supabase_db_${projectId}` : "supabase_db_";
159
+ }
160
+ /**
161
+ * The local stack's API port, published by its Kong container. Mirrors
162
+ * `env-runtime/load`'s `LOCAL_STACK_PORT`, which this module cannot import
163
+ * statically (that package is an optional peer, loaded on demand).
164
+ */
165
+ const STACK_API_PORT = 54321;
166
+ function defaultExec(file, args) {
167
+ try {
168
+ return execSync(file, args, {
169
+ stdio: [
170
+ "ignore",
171
+ "pipe",
172
+ "ignore"
173
+ ],
174
+ timeout: 3e3
175
+ });
176
+ } catch {
177
+ return null;
178
+ }
179
+ }
180
+ /**
181
+ * `docker ps --format '{{.Names}}'`, split into trimmed, non-empty names —
182
+ * or `null` when Docker could not be read at all (no daemon, not
183
+ * installed, timed out). With `publish`, only the containers publishing that
184
+ * host port. `execute` is injectable for tests, mirroring `environment.ts`'s
185
+ * own probes.
186
+ */
187
+ function listContainerNames(publish, execute = defaultExec) {
188
+ const out = execute("docker", [
189
+ "ps",
190
+ ...publish === void 0 ? [] : ["--filter", `publish=${publish}`],
191
+ "--format",
192
+ "{{.Names}}"
193
+ ]);
194
+ if (out === null) return null;
195
+ return out.split("\n").map((name) => name.trim()).filter((name) => name.length > 0);
196
+ }
197
+ /**
198
+ * Finds the `supabase_kong_<id>` container among `names` whose id differs
199
+ * from `projectId` — the signature of a stack started from a DIFFERENT
200
+ * Supabase project (this same repo before/after a rename, or another
201
+ * project entirely) holding the shared ports. Kong is the container that
202
+ * publishes the API port, so callers pass the names `listContainerNames`
203
+ * returns for `STACK_API_PORT`: that names the stack actually on 54321,
204
+ * not just any Supabase stack on the machine.
205
+ *
206
+ * Returns that foreign id, or `null` when every matching container belongs
207
+ * to this project, none match at all, or `projectId` itself could not be
208
+ * read — with no known id of our own, there is nothing to compare against,
209
+ * and guessing would risk telling a contributor their OWN stack is
210
+ * foreign.
211
+ */
212
+ function foreignStackProjectId(names, projectId) {
213
+ if (projectId === null) return null;
214
+ for (const name of names) {
215
+ const match = /^supabase_kong_(.+)$/.exec(name);
216
+ if (!match) continue;
217
+ const id = match[1];
218
+ if (id !== projectId) return id;
219
+ }
220
+ return null;
221
+ }
222
+ /**
223
+ * The actionable message for a detected foreign stack — shared by
224
+ * `db/generated-env.ts` (a failed `supabase status -o env`) and `stack.ts`
225
+ * (a failed `supabase start`), so both name the same fix in the same
226
+ * words.
227
+ */
228
+ function foreignStackMessage(foreignProjectId) {
229
+ return `The stack on port ${STACK_API_PORT} belongs to project "${foreignProjectId}", not this checkout's. Stop it with \`supabase stop --project-id ${foreignProjectId}\` then \`pnpm devtools supabase start\`.`;
230
+ }
231
+ //#endregion
8
232
  //#region ../cli-core/src/dry-run.ts
9
233
  const DRY_RUN_FLAG = "--dry-run";
10
234
  /** Commands that forward everything after their name to another tool. */
@@ -110,7 +334,7 @@ function runInGroup(command, args, opts = {}) {
110
334
  });
111
335
  }
112
336
  return new Promise((resolve) => {
113
- const child = spawn(command, [...args], {
337
+ const child = spawnProcess(command, args, {
114
338
  stdio: opts.stdio ?? "inherit",
115
339
  cwd: opts.cwd,
116
340
  env: opts.env,
@@ -188,111 +412,6 @@ function reportRan(command, args, result) {
188
412
  const status = result.code === 0 ? "" : ` (exit ${result.code})`;
189
413
  process.stderr.write(`Ran: ${formatCommand(command, args)}${status}\n`);
190
414
  }
191
- /** The directory (relative to a Backstage root) holding the DevDogsUGA checkout. */
192
- const DEVDOGSUGA_LINK = "devdogsuga";
193
- var DevdogsugaMissingError = class extends Error {
194
- constructor(path) {
195
- super(`The DevDogsUGA checkout is missing at ${path}. Run \`pnpm devdogsuga\` (links the sibling clone, or \$DEVDOGSUGA_DIR) or \`pnpm install\` in the Backstage root first.`);
196
- this.name = "DevdogsugaMissingError";
197
- }
198
- };
199
- /** The kind of repo `dir` is the root of, by its `package.json` name; null if neither. */
200
- function repoKindOf(dir) {
201
- try {
202
- const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
203
- if (pkg.name === "devdogs-monorepo") return "devdogsuga";
204
- if (pkg.name === "backstage") return "backstage";
205
- } catch {}
206
- return null;
207
- }
208
- function isDir(path) {
209
- try {
210
- return statSync(path).isDirectory();
211
- } catch {
212
- return false;
213
- }
214
- }
215
- /**
216
- * The layout of the repo rooted at `root`. Pure: nothing is memoized, so tests
217
- * can build fixtures freely. An unrecognised package name is treated as
218
- * DevDogsUGA (the contract fixtures and every pre-Backstage caller).
219
- */
220
- function layoutAt(root) {
221
- const kind = repoKindOf(root) === "backstage" ? "backstage" : "devdogsuga";
222
- const sibling = join(root, DEVDOGSUGA_LINK);
223
- const hasDevdogsuga = kind === "devdogsuga" || isDir(sibling);
224
- const devdogsugaRoot = kind === "devdogsuga" ? root : sibling;
225
- const appsDirs = [join(root, "apps")];
226
- if (kind === "backstage" && hasDevdogsuga) appsDirs.push(join(devdogsugaRoot, "apps"));
227
- return {
228
- kind,
229
- root,
230
- get devdogsugaRoot() {
231
- if (!hasDevdogsuga) throw new DevdogsugaMissingError(sibling);
232
- return devdogsugaRoot;
233
- },
234
- ...kind === "backstage" ? { backstageRoot: root } : {},
235
- hasDevdogsuga,
236
- appsDirs: appsDirs.filter(isDir),
237
- envMirrors: kind === "backstage" && hasDevdogsuga ? [devdogsugaRoot] : []
238
- };
239
- }
240
- /** `layout.devdogsugaRoot`, or null instead of a throw when the checkout is missing. */
241
- function devdogsugaRootOrNull(layout) {
242
- return layout.hasDevdogsuga ? layout.devdogsugaRoot : null;
243
- }
244
- let cached;
245
- let cachedFor;
246
- /** The layout of the repo the process is in (`findRepoRoot()`), memoized per root. */
247
- function resolveLayout() {
248
- const root = findRepoRoot();
249
- if (cached === void 0 || cachedFor !== root) {
250
- cached = layoutAt(root);
251
- cachedFor = root;
252
- }
253
- return cached;
254
- }
255
- /** Every directory under `appsDirs` (one app each), de-duplicated by name, sorted by name. */
256
- function listApps(layout = resolveLayout()) {
257
- const seen = /* @__PURE__ */ new Map();
258
- for (const parent of layout.appsDirs) for (const entry of readdirSync(parent, { withFileTypes: true })) {
259
- if (!entry.isDirectory()) continue;
260
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
261
- if (!seen.has(entry.name)) seen.set(entry.name, {
262
- name: entry.name,
263
- dir: join(parent, entry.name)
264
- });
265
- }
266
- return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
267
- }
268
- /** The directory of the app called `name`, or undefined when no repo has it. */
269
- function findApp(name, layout = resolveLayout()) {
270
- return listApps(layout).find((app) => app.name === name)?.dir;
271
- }
272
- /**
273
- * Resolves a workspace-relative path such as `workers.json`'s
274
- * `apps/schedule-builder` to a directory: the repo you are in first, then
275
- * DevDogsUGA's. When neither has it the first candidate is returned, so
276
- * callers get an ordinary ENOENT naming the path rather than a second error.
277
- */
278
- function resolveAppPath(relative, layout = resolveLayout()) {
279
- const first = join(layout.root, relative);
280
- if (existsSync(first)) return first;
281
- if (layout.kind === "backstage" && layout.hasDevdogsuga) {
282
- const second = join(layout.devdogsugaRoot, relative);
283
- if (existsSync(second)) return second;
284
- }
285
- return first;
286
- }
287
- /**
288
- * The pnpm workspace root holding the app called `name`: where
289
- * `pnpm --filter <name>` has to run. DevDogsUGA's root for its apps seen from a
290
- * Backstage checkout, `layout.root` otherwise.
291
- */
292
- function appWorkspaceRoot(name, layout = resolveLayout()) {
293
- const dir = findApp(name, layout);
294
- return dir === void 0 ? layout.root : dirname(dirname(dir));
295
- }
296
415
  //#endregion
297
416
  //#region ../cli-core/src/repo/resolve.ts
298
417
  /**
@@ -512,25 +631,14 @@ function getEnvSync() {
512
631
  }
513
632
  /** The env loader (`loadEnvironment` and the tier/file selection). Bundled. */
514
633
  function loadEnvLoad() {
515
- return import("./load-Czhayrsk.js");
634
+ return import("./load-yn7JCcS2.js");
516
635
  }
517
636
  /** The session policy (tier resolution, `enterEnvironment`). Bundled. */
518
637
  function loadEnvSession() {
519
- return import("./session-CmDxHEMn.js");
638
+ return import("./session-DzgtIg6K.js");
520
639
  }
521
640
  //#endregion
522
641
  //#region ../cli-core/src/db/run.ts
523
- /**
524
- * Shared helpers for running supabase CLI and pnpm commands.
525
- *
526
- * The supabase CLI is a workspace devDependency (not a global install), so
527
- * every invocation goes through `pnpm exec supabase`. Plain pnpm commands run
528
- * in `findRepoRoot()`; the supabase ones run in DevDogsUGA's root
529
- * (`supabaseRoot()`), where `supabase/config.toml` lives and where the CLI is
530
- * installed. From a Backstage checkout that is `<root>/devdogsuga`, so it needs
531
- * its own `pnpm install` there before any of these work.
532
- */
533
- const runFile = promisify(execFile);
534
642
  /** Where `supabase/` lives, and so the cwd of every supabase CLI call. */
535
643
  function supabaseRoot() {
536
644
  return resolveLayout().devdogsugaRoot;
@@ -561,7 +669,7 @@ function reportRuns(enabled) {
561
669
  * Pass `env` to run the child against a loaded tier rather than process.env. */
562
670
  function runWithStderr(args, env, cwd = findRepoRoot()) {
563
671
  return new Promise((resolve) => {
564
- const child = spawn("pnpm", args, {
672
+ const child = spawnProcess("pnpm", args, {
565
673
  stdio: [
566
674
  "inherit",
567
675
  "inherit",
@@ -571,8 +679,8 @@ function runWithStderr(args, env, cwd = findRepoRoot()) {
571
679
  ...env ? { env } : {}
572
680
  });
573
681
  let stderr = "";
574
- child.stderr.setEncoding("utf8");
575
- child.stderr.on("data", (chunk) => {
682
+ child.stderr?.setEncoding("utf8");
683
+ child.stderr?.on("data", (chunk) => {
576
684
  stderr += chunk;
577
685
  process.stderr.write(chunk);
578
686
  });
@@ -593,10 +701,7 @@ function runWithStderr(args, env, cwd = findRepoRoot()) {
593
701
  }
594
702
  /** Spawn a pnpm command, capture stdout, throw on non-zero exit. */
595
703
  async function capture(args, cwd = findRepoRoot()) {
596
- const { stdout } = await runFile("pnpm", args, {
597
- cwd,
598
- encoding: "utf8"
599
- });
704
+ const { stdout } = await exec("pnpm", args, { cwd });
600
705
  return stdout;
601
706
  }
602
707
  /** `pnpm exec supabase …` with inherited stdio. */
@@ -644,123 +749,4 @@ async function seedBuckets(conn) {
644
749
  return supabase("seed", "buckets", "--project-ref", conn.projectRef, "--linked");
645
750
  }
646
751
  //#endregion
647
- //#region ../cli-core/src/repo/supabase-project.ts
648
- /**
649
- * This repo's Supabase project id — read from `supabase/config.toml` — and
650
- * the container-name conventions the Supabase CLI derives from it.
651
- *
652
- * Shared by `environment.ts`'s adaptive-menu probe (does a stack answer for
653
- * THIS project?) and the foreign-stack detection in `db/generated-env.ts`
654
- * and `stack.ts` (does a DIFFERENT project's stack hold the shared ports? —
655
- * the case where `supabase status -o env` fails not because nothing is
656
- * running, but because what is running on 127.0.0.1:54321 belongs to
657
- * another workspace, or to this same repo before/after a `project_id`
658
- * rename). One project-id reader and one container-name parser, so both
659
- * questions agree on what "this project" means.
660
- */
661
- /**
662
- * Reads `project_id` out of `<repoRoot>/supabase/config.toml`, or `null`
663
- * when the file is missing or unparsable.
664
- *
665
- * Regex, not a TOML parser: it is one line, the shape has been stable
666
- * across every CLI version this repo has seen, and a parser on a path some
667
- * callers pay before their first real subprocess is a cost that stays
668
- * invisible until it is why the tool feels slow.
669
- */
670
- function readProjectId(repoRoot) {
671
- try {
672
- const path = join(repoRoot, "supabase", "config.toml");
673
- return /^\s*project_id\s*=\s*"([^"]+)"/m.exec(readFileSync(path, "utf8"))?.[1] ?? null;
674
- } catch {
675
- return null;
676
- }
677
- }
678
- /**
679
- * The Supabase CLI's container name prefix for a project id, or the bare
680
- * `supabase_db_` fallback when the id could not be read.
681
- *
682
- * Falling back to the bare prefix means a machine whose `config.toml`
683
- * cannot be read still detects *a* stack, at the cost of over-matching a
684
- * differently-named project — deliberate, and unchanged from this
685
- * function's original home in `environment.ts`: over-matching offers
686
- * `stop`/a foreign-stack hint for a stack that turns out to be this
687
- * project's own, which is harmless to see and decline, while
688
- * under-matching hides a real signal entirely.
689
- */
690
- function containerPrefix(projectId) {
691
- return projectId ? `supabase_db_${projectId}` : "supabase_db_";
692
- }
693
- /**
694
- * The local stack's API port, published by its Kong container. Mirrors
695
- * `env-runtime/load`'s `LOCAL_STACK_PORT`, which this module cannot import
696
- * statically (that package is an optional peer, loaded on demand).
697
- */
698
- const STACK_API_PORT = 54321;
699
- function defaultExec(file, args) {
700
- try {
701
- return execFileSync(file, args, {
702
- encoding: "utf8",
703
- stdio: [
704
- "ignore",
705
- "pipe",
706
- "ignore"
707
- ],
708
- timeout: 3e3
709
- });
710
- } catch {
711
- return null;
712
- }
713
- }
714
- /**
715
- * `docker ps --format '{{.Names}}'`, split into trimmed, non-empty names —
716
- * or `null` when Docker could not be read at all (no daemon, not
717
- * installed, timed out). With `publish`, only the containers publishing that
718
- * host port. `execute` is injectable for tests, mirroring `environment.ts`'s
719
- * own probes.
720
- */
721
- function listContainerNames(publish, execute = defaultExec) {
722
- const out = execute("docker", [
723
- "ps",
724
- ...publish === void 0 ? [] : ["--filter", `publish=${publish}`],
725
- "--format",
726
- "{{.Names}}"
727
- ]);
728
- if (out === null) return null;
729
- return out.split("\n").map((name) => name.trim()).filter((name) => name.length > 0);
730
- }
731
- /**
732
- * Finds the `supabase_kong_<id>` container among `names` whose id differs
733
- * from `projectId` — the signature of a stack started from a DIFFERENT
734
- * Supabase project (this same repo before/after a rename, or another
735
- * project entirely) holding the shared ports. Kong is the container that
736
- * publishes the API port, so callers pass the names `listContainerNames`
737
- * returns for `STACK_API_PORT`: that names the stack actually on 54321,
738
- * not just any Supabase stack on the machine.
739
- *
740
- * Returns that foreign id, or `null` when every matching container belongs
741
- * to this project, none match at all, or `projectId` itself could not be
742
- * read — with no known id of our own, there is nothing to compare against,
743
- * and guessing would risk telling a contributor their OWN stack is
744
- * foreign.
745
- */
746
- function foreignStackProjectId(names, projectId) {
747
- if (projectId === null) return null;
748
- for (const name of names) {
749
- const match = /^supabase_kong_(.+)$/.exec(name);
750
- if (!match) continue;
751
- const id = match[1];
752
- if (id !== projectId) return id;
753
- }
754
- return null;
755
- }
756
- /**
757
- * The actionable message for a detected foreign stack — shared by
758
- * `db/generated-env.ts` (a failed `supabase status -o env`) and `stack.ts`
759
- * (a failed `supabase start`), so both name the same fix in the same
760
- * words.
761
- */
762
- function foreignStackMessage(foreignProjectId) {
763
- return `The stack on port ${STACK_API_PORT} belongs to project "${foreignProjectId}", not this checkout's. Stop it with \`supabase stop --project-id ${foreignProjectId}\` then \`pnpm devtools supabase start\`.`;
764
- }
765
- //#endregion
766
- export { dryRunKind as A, layoutAt as C, formatCommand as D, resolveLayout as E, resolveDryRun as M, setDryRun as N, reportRan as O, wouldRunLine as P, findApp as S, resolveAppPath as T, loadEnvLoad as _, listContainerNames as a, appWorkspaceRoot as b, reportRuns as c, seedBuckets as d, supabase as f, loadEnv as g, getEnvSync as h, foreignStackProjectId as i, isDryRun as j, runInGroup as k, run as l, supabaseRoot as m, containerPrefix as n, readProjectId as o, supabaseCapture as p, foreignStackMessage as r, dbPush as s, STACK_API_PORT as t, runWithStderr as u, loadEnvSession as v, listApps as w, devdogsugaRootOrNull as x, repoPeerUrl as y };
752
+ export { findApp as A, containerPrefix as C, readProjectId as D, listContainerNames as E, listApps as M, resolveAppPath as N, appWorkspaceRoot as O, resolveLayout as P, STACK_API_PORT as S, foreignStackProjectId as T, dryRunKind as _, seedBuckets as a, setDryRun as b, supabaseRoot as c, loadEnvLoad as d, loadEnvSession as f, runInGroup as g, reportRan as h, runWithStderr as i, layoutAt as j, devdogsugaRootOrNull as k, getEnvSync as l, formatCommand as m, reportRuns as n, supabase as o, repoPeerUrl as p, run as r, supabaseCapture as s, dbPush as t, loadEnv as u, isDryRun as v, foreignStackMessage as w, wouldRunLine as x, resolveDryRun as y };
@@ -1,4 +1,4 @@
1
- import { _ as fileFor, d as loadEnvironment, f as parseRawAssignments, h as DEPLOY_ENVIRONMENTS, p as probeLocalStack, t as DEV_DB_ENV, u as isDevDatabase, v as isDeployEnvironment } from "./load-Cp8AMERM.js";
1
+ import { d as loadEnvironment, g as DEPLOY_ENVIRONMENTS, m as probeLocalStack, p as parseRawAssignments, t as DEV_DB_ENV, u as isDevDatabase, v as fileFor, y as isDeployEnvironment } from "./load-Z2CXCpyx.js";
2
2
  //#region ../cli-core/src/env-runtime/ask.ts
3
3
  /**
4
4
  * The interactive half of session resolution, shared by `with-env` and the
@@ -1,2 +1,2 @@
1
- import { a as parseSessionSelector, c as rememberDevDatabase, i as enterEnvironment, l as rememberedDevDatabase, n as availableTiers, o as resolveSessionTier, r as developmentRemoteCandidate, s as askSession, t as SESSION_SELECTORS } from "./session-rbONwFvY.js";
1
+ import { a as parseSessionSelector, c as rememberDevDatabase, i as enterEnvironment, l as rememberedDevDatabase, n as availableTiers, o as resolveSessionTier, r as developmentRemoteCandidate, s as askSession, t as SESSION_SELECTORS } from "./session-CuexI1f9.js";
2
2
  export { SESSION_SELECTORS, askSession, availableTiers, developmentRemoteCandidate, enterEnvironment, parseSessionSelector, rememberDevDatabase, rememberedDevDatabase, resolveSessionTier };
@@ -0,0 +1,100 @@
1
+ import crossSpawn from "cross-spawn";
2
+ //#region ../cli-core/src/spawn.ts
3
+ /** `child_process.spawn`, but able to start Windows `.cmd` shims. */
4
+ function spawnProcess(command, args, options = {}) {
5
+ return crossSpawn(command, [...args], options);
6
+ }
7
+ function execError(message, extra) {
8
+ return Object.assign(new Error(message), {
9
+ stdout: "",
10
+ stderr: "",
11
+ ...extra
12
+ });
13
+ }
14
+ /**
15
+ * `execFileSync(command, args, { encoding: "utf8" })` for a command that may
16
+ * be a Windows shim. Returns stdout; throws an {@link ExecError} when the
17
+ * program cannot start (`code: "ENOENT"`), times out, or exits non-zero.
18
+ */
19
+ function execSync(command, args, options = {}) {
20
+ const result = crossSpawn.sync(command, [...args], {
21
+ cwd: options.cwd,
22
+ env: options.env,
23
+ timeout: options.timeout,
24
+ encoding: "utf8",
25
+ stdio: options.stdio ?? [
26
+ "ignore",
27
+ "pipe",
28
+ "ignore"
29
+ ]
30
+ });
31
+ const stdout = typeof result.stdout === "string" ? result.stdout : "";
32
+ const stderr = typeof result.stderr === "string" ? result.stderr : "";
33
+ if (result.error) throw execError(result.error.message, {
34
+ code: result.error.code,
35
+ stdout,
36
+ stderr
37
+ });
38
+ if (result.status !== 0) throw execError(`Command failed: ${command} ${args.join(" ")}${stderr ? `\n${stderr}` : ""}`, {
39
+ code: result.status ?? void 0,
40
+ status: result.status,
41
+ stdout,
42
+ stderr
43
+ });
44
+ return stdout;
45
+ }
46
+ /** The async twin of {@link execSync}: resolves `{ stdout, stderr }`. */
47
+ function exec(command, args, options = {}) {
48
+ return new Promise((resolve, reject) => {
49
+ const child = crossSpawn(command, [...args], {
50
+ cwd: options.cwd,
51
+ env: options.env,
52
+ stdio: options.stdio ?? [
53
+ "ignore",
54
+ "pipe",
55
+ "pipe"
56
+ ]
57
+ });
58
+ let stdout = "";
59
+ let stderr = "";
60
+ let timedOut = false;
61
+ const timer = options.timeout === void 0 ? void 0 : setTimeout(() => {
62
+ timedOut = true;
63
+ child.kill();
64
+ }, options.timeout);
65
+ child.stdout?.setEncoding("utf8");
66
+ child.stderr?.setEncoding("utf8");
67
+ child.stdout?.on("data", (chunk) => {
68
+ stdout += chunk;
69
+ });
70
+ child.stderr?.on("data", (chunk) => {
71
+ stderr += chunk;
72
+ });
73
+ child.on("error", (error) => {
74
+ if (timer) clearTimeout(timer);
75
+ reject(execError(error.message, {
76
+ code: error.code,
77
+ stdout,
78
+ stderr
79
+ }));
80
+ });
81
+ child.on("close", (code) => {
82
+ if (timer) clearTimeout(timer);
83
+ if (code === 0 && !timedOut) {
84
+ resolve({
85
+ stdout,
86
+ stderr
87
+ });
88
+ return;
89
+ }
90
+ reject(execError(timedOut ? `Command timed out: ${command}` : `Command failed: ${command} ${args.join(" ")}${stderr ? `\n${stderr}` : ""}`, {
91
+ code: code ?? void 0,
92
+ status: code,
93
+ stdout,
94
+ stderr
95
+ }));
96
+ });
97
+ });
98
+ }
99
+ //#endregion
100
+ export { execSync as n, spawnProcess as r, exec as t };
@@ -1,4 +1,4 @@
1
- import { E as resolveLayout, _ as loadEnvLoad, a as listContainerNames, d as seedBuckets, f as supabase, i as foreignStackProjectId, j as isDryRun, o as readProjectId, p as supabaseCapture, r as foreignStackMessage, t as STACK_API_PORT, v as loadEnvSession } from "./supabase-project-BoJKMCxL.js";
1
+ import { D as readProjectId, E as listContainerNames, P as resolveLayout, S as STACK_API_PORT, T as foreignStackProjectId, a as seedBuckets, d as loadEnvLoad, f as loadEnvSession, o as supabase, s as supabaseCapture, v as isDryRun, w as foreignStackMessage } from "./run-CRBte7p0.js";
2
2
  import { join } from "node:path";
3
3
  import { writeFile } from "node:fs/promises";
4
4
  //#region src/db/session-refresh.ts
@@ -0,0 +1,2 @@
1
+ import { t as runStackCommand } from "./stack-BRevXgI3.js";
2
+ export { runStackCommand };