@devdogsuga/devtools 0.1.25 → 0.1.27

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 (271) hide show
  1. package/README.md +72 -11
  2. package/bin/devtools.mjs +4 -4
  3. package/dist/cli-CZKkNHK5.js +6619 -0
  4. package/dist/failure-log-BBPGejQv.js +256 -0
  5. package/dist/launch.js +267 -281
  6. package/dist/local-env-D8HC2JK_.js +351 -0
  7. package/dist/local-env-DrBCXqD8.js +2 -0
  8. package/dist/menu-CQBsQRgH.js +1684 -0
  9. package/dist/peer-redirect-hooks.js +15 -0
  10. package/dist/peers-RBplwovA.js +229 -0
  11. package/dist/root-C2OmZDwD.js +94 -0
  12. package/dist/stack-Bx-55oi_.js +2 -0
  13. package/dist/stack-BynCgRVS.js +181 -0
  14. package/dist/supabase-project-0knM0mqd.js +426 -0
  15. package/dist/telemetry-C4foD8MD.js +249 -0
  16. package/dist/telemetry.js +2 -148
  17. package/package.json +10 -29
  18. package/bin/devtools-ci-bare.mjs +0 -48
  19. package/bin/devtools-ci.mjs +0 -31
  20. package/dist/args.d.ts +0 -26
  21. package/dist/args.js +0 -78
  22. package/dist/bws/bw.d.ts +0 -18
  23. package/dist/bws/bw.js +0 -70
  24. package/dist/bws/client.d.ts +0 -43
  25. package/dist/bws/client.js +0 -363
  26. package/dist/bws/environments.d.ts +0 -96
  27. package/dist/bws/environments.js +0 -111
  28. package/dist/bws/pace.d.ts +0 -25
  29. package/dist/bws/pace.js +0 -43
  30. package/dist/bws/retry.d.ts +0 -12
  31. package/dist/bws/retry.js +0 -39
  32. package/dist/bws/store.d.ts +0 -1
  33. package/dist/bws/store.js +0 -32
  34. package/dist/bws/token.d.ts +0 -31
  35. package/dist/bws/token.js +0 -88
  36. package/dist/bws/vault.d.ts +0 -29
  37. package/dist/bws/vault.js +0 -200
  38. package/dist/catalog.d.ts +0 -57
  39. package/dist/catalog.js +0 -57
  40. package/dist/cf/build.d.ts +0 -13
  41. package/dist/cf/build.js +0 -65
  42. package/dist/cf/commands.d.ts +0 -1
  43. package/dist/cf/commands.js +0 -172
  44. package/dist/cf/local-env.d.ts +0 -58
  45. package/dist/cf/local-env.js +0 -177
  46. package/dist/ci.d.ts +0 -1
  47. package/dist/ci.js +0 -328
  48. package/dist/cli.d.ts +0 -11
  49. package/dist/cli.js +0 -1094
  50. package/dist/commands.d.ts +0 -261
  51. package/dist/commands.js +0 -1318
  52. package/dist/completions.d.ts +0 -4
  53. package/dist/completions.js +0 -110
  54. package/dist/cron/commands.d.ts +0 -47
  55. package/dist/cron/commands.js +0 -372
  56. package/dist/cron/discovery.d.ts +0 -55
  57. package/dist/cron/discovery.js +0 -85
  58. package/dist/cron/schema.d.ts +0 -45
  59. package/dist/cron/schema.js +0 -35
  60. package/dist/db/config-push.d.ts +0 -8
  61. package/dist/db/config-push.js +0 -11
  62. package/dist/db/connection.d.ts +0 -79
  63. package/dist/db/connection.js +0 -114
  64. package/dist/db/exec.d.ts +0 -1
  65. package/dist/db/exec.js +0 -11
  66. package/dist/db/generate-types.d.ts +0 -1
  67. package/dist/db/generate-types.js +0 -4
  68. package/dist/db/generated-env.d.ts +0 -69
  69. package/dist/db/generated-env.js +0 -113
  70. package/dist/db/introspect.d.ts +0 -1
  71. package/dist/db/introspect.js +0 -122
  72. package/dist/db/local-env.d.ts +0 -65
  73. package/dist/db/local-env.js +0 -23
  74. package/dist/db/new-migration.d.ts +0 -8
  75. package/dist/db/new-migration.js +0 -69
  76. package/dist/db/pooler.d.ts +0 -23
  77. package/dist/db/pooler.js +0 -55
  78. package/dist/db/run.d.ts +0 -68
  79. package/dist/db/run.js +0 -156
  80. package/dist/db/seed-buckets.d.ts +0 -2
  81. package/dist/db/seed-buckets.js +0 -4
  82. package/dist/db/seed-production.d.ts +0 -8
  83. package/dist/db/seed-production.js +0 -79
  84. package/dist/db/seed-roles.d.ts +0 -7
  85. package/dist/db/seed-roles.js +0 -33
  86. package/dist/db/session-refresh.d.ts +0 -43
  87. package/dist/db/session-refresh.js +0 -40
  88. package/dist/deploy/migrations.d.ts +0 -20
  89. package/dist/deploy/migrations.js +0 -68
  90. package/dist/deploy/orphans.d.ts +0 -20
  91. package/dist/deploy/orphans.js +0 -177
  92. package/dist/deploy/preflight.d.ts +0 -53
  93. package/dist/deploy/preflight.js +0 -189
  94. package/dist/deploy/report.d.ts +0 -26
  95. package/dist/deploy/report.js +0 -70
  96. package/dist/deploy/require-planner.d.ts +0 -2
  97. package/dist/deploy/require-planner.js +0 -60
  98. package/dist/deploy/require-token.d.ts +0 -15
  99. package/dist/deploy/require-token.js +0 -78
  100. package/dist/deploy/secrets-file.d.ts +0 -17
  101. package/dist/deploy/secrets-file.js +0 -166
  102. package/dist/deploy/write-env.d.ts +0 -40
  103. package/dist/deploy/write-env.js +0 -395
  104. package/dist/docs/index-pages.d.ts +0 -38
  105. package/dist/docs/index-pages.js +0 -186
  106. package/dist/emails/commands.d.ts +0 -15
  107. package/dist/emails/commands.js +0 -130
  108. package/dist/emails/email-types.d.ts +0 -13
  109. package/dist/emails/email-types.js +0 -1
  110. package/dist/emails/fixtures.d.ts +0 -20
  111. package/dist/emails/fixtures.js +0 -20
  112. package/dist/env/audit.d.ts +0 -206
  113. package/dist/env/audit.js +0 -436
  114. package/dist/env/cloudflare.d.ts +0 -21
  115. package/dist/env/cloudflare.js +0 -61
  116. package/dist/env/commands.d.ts +0 -99
  117. package/dist/env/commands.js +0 -613
  118. package/dist/env/discovery.d.ts +0 -15
  119. package/dist/env/discovery.js +0 -239
  120. package/dist/env/document.d.ts +0 -119
  121. package/dist/env/document.js +0 -323
  122. package/dist/env/example.d.ts +0 -68
  123. package/dist/env/example.js +0 -605
  124. package/dist/env/selection.d.ts +0 -105
  125. package/dist/env/selection.js +0 -228
  126. package/dist/env-entry.d.ts +0 -49
  127. package/dist/env-entry.js +0 -204
  128. package/dist/environment-doctor.d.ts +0 -45
  129. package/dist/environment-doctor.js +0 -429
  130. package/dist/environment.d.ts +0 -92
  131. package/dist/environment.js +0 -185
  132. package/dist/fingerprint.d.ts +0 -10
  133. package/dist/fingerprint.js +0 -18
  134. package/dist/gen/campus-map.d.ts +0 -1
  135. package/dist/gen/campus-map.js +0 -473
  136. package/dist/gen/commands.d.ts +0 -1
  137. package/dist/gen/commands.js +0 -25
  138. package/dist/gen/hypno.d.ts +0 -1
  139. package/dist/gen/hypno.js +0 -134
  140. package/dist/gh/client.d.ts +0 -80
  141. package/dist/gh/client.js +0 -259
  142. package/dist/gh/environments.d.ts +0 -83
  143. package/dist/gh/environments.js +0 -178
  144. package/dist/gh/rulesets/actors.d.ts +0 -14
  145. package/dist/gh/rulesets/actors.js +0 -69
  146. package/dist/gh/rulesets/api.d.ts +0 -15
  147. package/dist/gh/rulesets/api.js +0 -104
  148. package/dist/gh/rulesets/commands.d.ts +0 -3
  149. package/dist/gh/rulesets/commands.js +0 -203
  150. package/dist/gh/rulesets/desired.d.ts +0 -112
  151. package/dist/gh/rulesets/desired.js +0 -271
  152. package/dist/gh/rulesets/diff.d.ts +0 -65
  153. package/dist/gh/rulesets/diff.js +0 -170
  154. package/dist/gh/rulesets/types.d.ts +0 -76
  155. package/dist/gh/rulesets/types.js +0 -13
  156. package/dist/gh/settings/api.d.ts +0 -40
  157. package/dist/gh/settings/api.js +0 -180
  158. package/dist/gh/settings/commands.d.ts +0 -1
  159. package/dist/gh/settings/commands.js +0 -254
  160. package/dist/gh/settings/desired.d.ts +0 -53
  161. package/dist/gh/settings/desired.js +0 -43
  162. package/dist/gh/settings/diff.d.ts +0 -57
  163. package/dist/gh/settings/diff.js +0 -161
  164. package/dist/gh/settings/types.d.ts +0 -92
  165. package/dist/gh/settings/types.js +0 -11
  166. package/dist/gh/settings/workflows.d.ts +0 -41
  167. package/dist/gh/settings/workflows.js +0 -128
  168. package/dist/grantRoot.d.ts +0 -42
  169. package/dist/grantRoot.js +0 -89
  170. package/dist/help.d.ts +0 -18
  171. package/dist/help.js +0 -169
  172. package/dist/images/commands.d.ts +0 -32
  173. package/dist/images/commands.js +0 -231
  174. package/dist/images/events.d.ts +0 -47
  175. package/dist/images/events.js +0 -116
  176. package/dist/images/graphics.d.ts +0 -70
  177. package/dist/images/graphics.js +0 -234
  178. package/dist/images/open-graph-types.d.ts +0 -75
  179. package/dist/images/open-graph-types.js +0 -1
  180. package/dist/images/prompts.d.ts +0 -34
  181. package/dist/images/prompts.js +0 -100
  182. package/dist/images/render.d.ts +0 -21
  183. package/dist/images/render.js +0 -61
  184. package/dist/images/select.d.ts +0 -64
  185. package/dist/images/select.js +0 -96
  186. package/dist/instance.d.ts +0 -69
  187. package/dist/instance.js +0 -102
  188. package/dist/invocation.d.ts +0 -49
  189. package/dist/invocation.js +0 -78
  190. package/dist/launch-ci.d.ts +0 -1
  191. package/dist/launch-ci.js +0 -90
  192. package/dist/launch.d.ts +0 -18
  193. package/dist/menu.d.ts +0 -43
  194. package/dist/menu.js +0 -300
  195. package/dist/moderation.d.ts +0 -70
  196. package/dist/moderation.js +0 -128
  197. package/dist/oauth/browser.d.ts +0 -1
  198. package/dist/oauth/browser.js +0 -13
  199. package/dist/oauth/config.d.ts +0 -24
  200. package/dist/oauth/config.js +0 -24
  201. package/dist/oauth/connect-url.d.ts +0 -17
  202. package/dist/oauth/connect-url.js +0 -23
  203. package/dist/oauth/db.d.ts +0 -37
  204. package/dist/oauth/db.js +0 -108
  205. package/dist/oauth/device.d.ts +0 -93
  206. package/dist/oauth/device.js +0 -198
  207. package/dist/oauth/discovery.d.ts +0 -28
  208. package/dist/oauth/discovery.js +0 -54
  209. package/dist/oauth/env-file.d.ts +0 -6
  210. package/dist/oauth/env-file.js +0 -35
  211. package/dist/oauth/exchange.d.ts +0 -43
  212. package/dist/oauth/exchange.js +0 -93
  213. package/dist/oauth/label.d.ts +0 -1
  214. package/dist/oauth/label.js +0 -25
  215. package/dist/oauth/loopback.d.ts +0 -52
  216. package/dist/oauth/loopback.js +0 -168
  217. package/dist/oauth/pkce.d.ts +0 -6
  218. package/dist/oauth/pkce.js +0 -34
  219. package/dist/oauth/target.d.ts +0 -54
  220. package/dist/oauth/target.js +0 -102
  221. package/dist/oauth/transport.d.ts +0 -41
  222. package/dist/oauth/transport.js +0 -32
  223. package/dist/oauth/wizard.d.ts +0 -40
  224. package/dist/oauth/wizard.js +0 -578
  225. package/dist/persona.d.ts +0 -18
  226. package/dist/persona.js +0 -221
  227. package/dist/pick.d.ts +0 -6
  228. package/dist/pick.js +0 -64
  229. package/dist/pipes.d.ts +0 -1
  230. package/dist/pipes.js +0 -25
  231. package/dist/planner/checks.d.ts +0 -26
  232. package/dist/planner/checks.js +0 -104
  233. package/dist/planner/commands.d.ts +0 -10
  234. package/dist/planner/commands.js +0 -367
  235. package/dist/planner/db.d.ts +0 -15
  236. package/dist/planner/db.js +0 -33
  237. package/dist/planner/role.d.ts +0 -33
  238. package/dist/planner/role.js +0 -68
  239. package/dist/repo/peer-redirect-hooks.d.ts +0 -16
  240. package/dist/repo/peer-redirect-hooks.js +0 -10
  241. package/dist/repo/peer-redirect.d.ts +0 -4
  242. package/dist/repo/peer-redirect.js +0 -26
  243. package/dist/repo/peers.d.ts +0 -39
  244. package/dist/repo/peers.js +0 -139
  245. package/dist/repo/resolve.d.ts +0 -41
  246. package/dist/repo/resolve.js +0 -152
  247. package/dist/repo/root.d.ts +0 -23
  248. package/dist/repo/root.js +0 -91
  249. package/dist/repo/source.d.ts +0 -14
  250. package/dist/repo/source.js +0 -54
  251. package/dist/repo/supabase-project.d.ts +0 -60
  252. package/dist/repo/supabase-project.js +0 -124
  253. package/dist/repo/tsx-loader.d.ts +0 -6
  254. package/dist/repo/tsx-loader.js +0 -41
  255. package/dist/run/pick.d.ts +0 -90
  256. package/dist/run/pick.js +0 -664
  257. package/dist/setup.d.ts +0 -1
  258. package/dist/setup.js +0 -280
  259. package/dist/stack.d.ts +0 -48
  260. package/dist/stack.js +0 -403
  261. package/dist/telemetry.d.ts +0 -59
  262. package/dist/tier.d.ts +0 -40
  263. package/dist/tier.js +0 -96
  264. package/dist/ui.d.ts +0 -40
  265. package/dist/ui.js +0 -71
  266. package/dist/version.d.ts +0 -7
  267. package/dist/version.js +0 -17
  268. package/dist/workers.d.ts +0 -5
  269. package/dist/workers.js +0 -33
  270. package/dist/workflows/commands.d.ts +0 -54
  271. package/dist/workflows/commands.js +0 -763
package/dist/stack.js DELETED
@@ -1,403 +0,0 @@
1
- /**
2
- * Database commands, over the session's database.
3
- *
4
- * Previously delegated to `@devdogsuga/supabase` package scripts by name,
5
- * then to a `--target local|remote` flag; now every data command acts on the
6
- * ONE database the session entered (see `db/connection.ts`), passed to the
7
- * supabase CLI as an explicit `--db-url`. That uniformity is load-bearing:
8
- * the CLI's own defaults disagree per subcommand (`db push` defaults to the
9
- * LINKED project, `db reset` to `--local`), and `--db-url` is the one
10
- * spelling that can neither fall back to `supabase link`'s ambient state
11
- * nor quietly pick a different database than the session says.
12
- *
13
- * The stack-lifecycle commands (`start`/`stop`/`restart`) are the deliberate
14
- * exception: they act on this machine's Docker containers, which no DB_URL
15
- * names, and they run under any session — starting your local stack while
16
- * the session targets staging is odd but harmless, and refusing it would
17
- * block the one command that fixes an offline-local session.
18
- */
19
- import { existsSync, rmSync } from "node:fs";
20
- import { writeFile } from "node:fs/promises";
21
- import { join } from "node:path";
22
- import { describeEnvironment, probeEnvironment } from "./environment.js";
23
- import { findRepoRoot } from "./repo/root.js";
24
- import { foreignStackMessage, foreignStackProjectId, listContainerNames, STACK_API_PORT, readProjectId, } from "./repo/supabase-project.js";
25
- import { dbPush, generateTypes, seedBuckets, supabase, supabaseCapture, } from "./db/run.js";
26
- import { describeDbTarget, isLocalConnection, } from "./db/connection.js";
27
- import { refreshSessionEnv } from "./db/session-refresh.js";
28
- import { runSeedProduction } from "./db/seed-production.js";
29
- import { originReachable, resolveBaseUrl } from "./cron/commands.js";
30
- import { ensureGeneratedEnvFile, realEnsureGeneratedEnvDeps, } from "./db/generated-env.js";
31
- import { loadEnvLoad } from "./repo/peers.js";
32
- // Scope order, matching `db`'s subcommands in `commands.ts`: the four that
33
- // act on the Supabase stack (`connect` is handled separately below — it
34
- // takes a positional ref), then the two that write the Postgres database
35
- // inside the session's endpoint.
36
- export const STACK_COMMANDS = [
37
- "start",
38
- "stop",
39
- "restart",
40
- "status",
41
- "migrate",
42
- "reset",
43
- ];
44
- // ── Implementations ──────────────────────────────────────────────────────────
45
- /**
46
- * A running Docker container whose name says it belongs to a DIFFERENT
47
- * Supabase project than this checkout's own `config.toml` — the signature
48
- * of a foreign stack holding the shared ports (see
49
- * `repo/supabase-project.ts`'s header). `undefined` when nothing points
50
- * that way, including when Docker or `config.toml` could not be read at
51
- * all: with no signal either way, `startLocalStack`'s own failure and the
52
- * Supabase CLI's own output are still the reader's best explanation.
53
- */
54
- function foreignStackHint() {
55
- const names = listContainerNames(STACK_API_PORT);
56
- if (names === null)
57
- return undefined;
58
- const foreign = foreignStackProjectId(names, readProjectId(findRepoRoot()));
59
- return foreign === null ? undefined : foreignStackMessage(foreign);
60
- }
61
- /**
62
- * `wroteEnvFile` is split out from `code` on purpose: `.env.generated` is
63
- * written to disk BEFORE `seedBuckets` runs, so a nonzero `code` from
64
- * `seedBuckets` alone does not mean the file on disk is unchanged — the
65
- * fresh connection block is already there, a later `db start` retry or the
66
- * probe table would already see it, and this process's OWN entered
67
- * environment is now the stale one. `afterLocalStackChange` below refreshes
68
- * whenever the file changed, independently of whether the command as a whole
69
- * succeeded, and still reports the failing code so the caller does not
70
- * mistake a seed failure for success.
71
- *
72
- * `hint` is set when `supabase start` itself fails (before anything here
73
- * could have written `.env.generated`) AND a foreign project's stack is
74
- * holding the ports — the same signal `db/generated-env.ts` surfaces for a
75
- * failed `supabase status -o env`, named here too so `db start` explains
76
- * itself instead of leaving only the bare Supabase CLI error.
77
- */
78
- async function startLocalStack() {
79
- const code = await supabase("start");
80
- if (code !== 0) {
81
- const hint = foreignStackHint();
82
- return hint === undefined
83
- ? { code, wroteEnvFile: false }
84
- : { code, wroteEnvFile: false, hint };
85
- }
86
- // Write the local stack's connection details so with-env can load them.
87
- let env;
88
- try {
89
- env = await supabaseCapture("status", "-o", "env");
90
- }
91
- catch {
92
- return { code: 1, wroteEnvFile: false };
93
- }
94
- await writeFile(join(findRepoRoot(), ".env.generated"), env);
95
- const bucketsCode = await seedBuckets({ kind: "local" });
96
- return { code: bucketsCode, wroteEnvFile: true };
97
- }
98
- async function stopLocalStack() {
99
- const code = await supabase("stop");
100
- if (code !== 0)
101
- return code;
102
- rmSync(join(findRepoRoot(), ".env.generated"), { force: true });
103
- return 0;
104
- }
105
- /**
106
- * `db connect [<project-ref>]` — run `supabase link` for whoever drives the
107
- * bare supabase CLI by hand. Nothing in devtools reads what it writes any
108
- * more (see `db/connection.ts`'s header); it survives as a convenience, not
109
- * a dependency.
110
- */
111
- export async function connectRemoteProject(ref) {
112
- const projectRef = ref ?? process.env.PROJECT_REF;
113
- if (!projectRef) {
114
- process.stderr.write("devtools db connect: no project ref given, and PROJECT_REF is not set. " +
115
- "Pass one, or add PROJECT_REF to your .env file.\n");
116
- return 1;
117
- }
118
- return supabase("link", "--project-ref", projectRef);
119
- }
120
- /** The `seed buckets` shape this connection implies — `--db-url` does not
121
- * exist for that subcommand, so it is the one data command still keyed on
122
- * local-vs-hosted rather than on the URL itself. */
123
- function bucketsShape(connection) {
124
- return isLocalConnection(connection)
125
- ? { kind: "local" }
126
- : { kind: "remote", projectRef: connection.projectRef };
127
- }
128
- async function pushMigrations(connection) {
129
- // The bare push (shared with CI's `deploy migrate`) then the type
130
- // regeneration the contributor path layers on top — see `dbPush`'s header
131
- // for why the two are split.
132
- const code = await dbPush(connection.dbUrl);
133
- if (code !== 0)
134
- return code;
135
- return generateTypes(connection.dbUrl);
136
- }
137
- /**
138
- * ⚠️ SAFETY-CRITICAL: drops and re-migrates `connection.dbUrl`. The caller
139
- * (`cli.ts`'s `runStack`) has already confirmed the session target —
140
- * including the hard production gate — before this ever runs.
141
- *
142
- * A non-development target gets `--no-seed` on the reset itself, followed by
143
- * an explicit `runSeedProduction` — the same two steps `db seed production`
144
- * runs on its own (see `seed-production.ts`) — rather than letting the bare
145
- * `supabase db reset` apply whatever `config.toml`'s `[db.seed]` happens to
146
- * list. That is deliberately belt-and-suspenders: `[db.seed]` today lists
147
- * only `supabase/seed/production`, so the bare reset would already do the
148
- * right thing, but that is a property of the CURRENT config, not of this
149
- * function. An older checkout, or a config edited to add
150
- * `supabase/seed/development` back for some local-only reason, must still be
151
- * structurally unable to run development's password-login seeds against a
152
- * hosted, non-dev database — the one seed directory that must never reach
153
- * staging or production, named in that directory's own header. Development
154
- * resets are untouched: they keep applying whatever `[db.seed]` lists, same
155
- * as always.
156
- *
157
- * Meetings and workshops are NOT among the tables `supabase/seed/*.sql`
158
- * populates -- they come from `@devdogsuga/events` via
159
- * `reconcileFromConfig`, an authenticated platform route rather than a
160
- * devtools-side function this CLI can call directly (it needs the app's
161
- * Drizzle client, relations and Sentry wiring, none of which belong in this
162
- * package). On any DEVELOPMENT reset -- local Docker or the shared remote dev
163
- * project alike -- this calls that route itself, over the same origin `cron
164
- * run` would use, once the reset and rebuild finish -- see
165
- * `reconcileConfigAfterReset` for what happens when nothing is listening yet.
166
- */
167
- async function reset(connection) {
168
- const isDev = connection.tier === "development";
169
- const code = await supabase("db", "reset", "--db-url", connection.dbUrl, ...(isDev ? [] : ["--no-seed"]));
170
- if (code !== 0)
171
- return { code, lines: [] };
172
- const types = await generateTypes(connection.dbUrl);
173
- if (types !== 0)
174
- return { code: types, lines: [] };
175
- const bucketsCode = await seedBuckets(bucketsShape(connection));
176
- if (bucketsCode !== 0)
177
- return { code: bucketsCode, lines: [] };
178
- if (!isDev) {
179
- const seedCode = await runSeedProduction(connection.dbUrl);
180
- if (seedCode !== 0)
181
- return { code: seedCode, lines: [] };
182
- return { code: 0, lines: [] };
183
- }
184
- return {
185
- code: 0,
186
- // Both development databases — local Docker and the shared remote dev
187
- // project (`--tier development:remote`) — rather than gated on
188
- // `isLocalConnection`. The platform dev server this hits is always local
189
- // (`resolveBaseUrl("platform", "development", …)` inside
190
- // `reconcileConfigAfterReset`); what varies with `devDatabase` is only
191
- // which Postgres that local server happens to be pointed at, and a
192
- // remote-dev reset leaves meetings and workshops just as unseeded as a
193
- // local one.
194
- lines: await reconcileConfigAfterReset(),
195
- };
196
- }
197
- /**
198
- * Best-effort trigger for `GET /cron/config-reconcile` against the local
199
- * platform dev server, so `db reset` leaves meetings and workshops seeded
200
- * whenever that server happens to already be up -- the common case for a
201
- * repeat reset during development, rather than a first clone. No
202
- * `CRON_SECRET` is sent because the route itself skips auth outside a
203
- * deployed `DEPLOY_ENV` (see that route's header); this is exactly the
204
- * unauthenticated local request `cron run` would send.
205
- *
206
- * When nothing answers yet -- most likely a first-time reset, before anyone
207
- * has run `pnpm --filter platform dev` -- this reports that instead of
208
- * silently leaving the tables empty, and names the manual step: start the
209
- * server, then either re-run this reset or fire the shared fifteen-minute
210
- * cron slot directly with `pnpm devtools cron run`.
211
- */
212
- export async function reconcileConfigAfterReset(deps = {
213
- reachable: originReachable,
214
- fetch: globalThis.fetch,
215
- }) {
216
- const { reachable, fetch: fetchImpl } = deps;
217
- const baseUrl = resolveBaseUrl("platform", "development", undefined, {});
218
- const manualStep = "Start the platform app (`pnpm --filter platform dev`) and either " +
219
- "re-run `pnpm devtools db reset` or run `pnpm devtools cron run --app " +
220
- "platform --cron '*/15 * * * *' --yes`.";
221
- if (!(await reachable(baseUrl))) {
222
- return [
223
- `Meetings and workshops are not seeded yet -- nothing is listening at ${baseUrl} ` +
224
- `to reconcile @devdogsuga/events into them. ${manualStep}`,
225
- ];
226
- }
227
- const url = new URL("/cron/config-reconcile", baseUrl).toString();
228
- let response;
229
- try {
230
- response = await fetchImpl(url);
231
- }
232
- catch (err) {
233
- return [
234
- `Config reconcile request to ${url} failed: ` +
235
- `${err instanceof Error ? err.message : String(err)}. ${manualStep}`,
236
- ];
237
- }
238
- if (!response.ok) {
239
- return [
240
- `Config reconcile answered HTTP ${response.status} at ${url}. ${manualStep}`,
241
- ];
242
- }
243
- const body = (await response.json());
244
- if (!body.success) {
245
- return [
246
- `Config reconcile ran but was aborted (${body.reason}) -- meetings and ` +
247
- "workshops are still empty. Check the platform dev server's console.",
248
- ];
249
- }
250
- return ["Meetings and workshops reconciled from @devdogsuga/events."];
251
- }
252
- /**
253
- * BUG 2's fix, applied at every point `start`/`stop`/`restart` can change
254
- * `.env.generated`: on success, refresh this process's entered environment
255
- * (see `db/session-refresh.ts`) so the rest of the session — including a
256
- * `db introspect` run right after this one — sees the stack's CURRENT
257
- * connection, not whatever `process.env` held at launch. A failed stack
258
- * command USUALLY changed nothing on disk, so by default there is nothing to
259
- * refresh.
260
- *
261
- * `wroteEnvFile` is the one exception: `startLocalStack` writes
262
- * `.env.generated` BEFORE the buckets-seed step that can still fail
263
- * afterwards, so a nonzero `code` from THAT failure does not mean the file on
264
- * disk is unchanged — see `startLocalStack`'s own doc. Passing `true` here
265
- * refreshes regardless of `code`, while the failing code itself still reaches
266
- * the caller untouched, so `db start` is still reported as failed even though
267
- * the session's environment was brought current.
268
- */
269
- async function afterLocalStackChange(code, wroteEnvFile = false) {
270
- if (code !== 0 && !wroteEnvFile)
271
- return [];
272
- return refreshSessionEnv();
273
- }
274
- // ── The local stack's lifecycle ──────────────────────────────────────────────
275
- /**
276
- * Stop, then start again.
277
- *
278
- * Two steps rather than one, because `supabase restart` does not exist. The
279
- * CLI's own answer to a changed `config.toml` is a stop/start pair. Doing it
280
- * here turns that into one menu entry, rather than two commands the contributor
281
- * has to know to run in that order.
282
- *
283
- * A failed stop short-circuits. Starting a stack that never went down would
284
- * report success and leave the config change unapplied, which is the one
285
- * outcome worse than a visible failure.
286
- */
287
- async function restartLocal() {
288
- const stopCode = await stopLocalStack();
289
- if (stopCode !== 0) {
290
- return {
291
- code: stopCode,
292
- lines: [
293
- "Stopping failed, so nothing was restarted. " +
294
- "Scroll up for the output from the Supabase CLI.",
295
- ],
296
- };
297
- }
298
- const { code, wroteEnvFile, hint } = await startLocalStack();
299
- const lines = await afterLocalStackChange(code, wroteEnvFile);
300
- return { code, lines: hint === undefined ? lines : [hint, ...lines] };
301
- }
302
- /**
303
- * What `status` says for a local session, now that it can answer for itself.
304
- *
305
- * `environment.ts` already reads the two facts that question is really
306
- * asking about, so this reports them and names the next step. When the
307
- * stack's containers are up but this checkout's own `.env.generated` is
308
- * missing — most often a stack another workspace started, sharing this
309
- * repo's `project_id` — this also attempts the same regeneration
310
- * `enterSessionEnvironment` (`env-entry.ts`) runs before every command, so
311
- * `db status` reports the file's ACTUAL state after trying to fix it,
312
- * rather than a stale "the stack is up" that leaves the absence a mystery.
313
- */
314
- async function localStatus() {
315
- const env = probeEnvironment();
316
- const lines = [describeEnvironment(env)];
317
- if (env.docker === "no") {
318
- lines.push("Start Docker, then `pnpm devtools db start` to bring the stack up.");
319
- return { code: 0, lines };
320
- }
321
- if (env.stack === "no") {
322
- lines.push("Nothing is running. `pnpm devtools db start` starts it.");
323
- return { code: 0, lines };
324
- }
325
- if (env.stack === "unknown") {
326
- lines.push("Could not read Docker. `supabase status` asks the stack directly.");
327
- return { code: 0, lines };
328
- }
329
- // env.stack === "yes"
330
- const repoRoot = findRepoRoot();
331
- if (existsSync(join(repoRoot, ".env.generated"))) {
332
- lines.push("The stack is up. `supabase status` prints its URLs and keys.");
333
- return { code: 0, lines };
334
- }
335
- const envLoad = await loadEnvLoad();
336
- const generated = await ensureGeneratedEnvFile("development", undefined, realEnsureGeneratedEnvDeps(envLoad.probeLocalStack));
337
- if (generated.outcome === "wrote") {
338
- lines.push(generated.line.replace(/^devtools: /, ""), "The stack is up. `supabase status` prints its URLs and keys.");
339
- }
340
- else if (generated.outcome === "foreign") {
341
- lines.push(generated.line.replace(/^devtools: /, ""));
342
- }
343
- else if (generated.outcome === "unreachable") {
344
- lines.push("The stack's containers are up but .env.generated could not be " +
345
- "regenerated — run `supabase status -o env` yourself to see why.");
346
- }
347
- else {
348
- // "skipped": Docker's container list said the stack is up, but nothing
349
- // answered the port probe — a race right after `db start`/`db restart`,
350
- // most likely. Nothing to regenerate from yet.
351
- lines.push("Docker reports the stack's containers running, but nothing is " +
352
- "answering on 127.0.0.1:54321 yet — try again in a moment.");
353
- }
354
- return { code: 0, lines };
355
- }
356
- /**
357
- * Runs a stack command, returning its exit code and anything to report.
358
- *
359
- * `connection` is present exactly when the command writes the database
360
- * (`migrate`, `reset`) — the caller (`cli.ts`'s `runStack`) resolves it,
361
- * because resolving means possibly refusing with a printed reason, and the
362
- * lifecycle commands must keep working with no resolvable database at all
363
- * (that is what `db start` is FOR). `status` receives whatever resolved,
364
- * or `null`, and degrades to machine facts.
365
- */
366
- export async function runStackCommand(command, connection) {
367
- if (command === "restart")
368
- return restartLocal();
369
- if (command === "stop") {
370
- const code = await stopLocalStack();
371
- return { code, lines: await afterLocalStackChange(code) };
372
- }
373
- if (command === "start") {
374
- const { code, wroteEnvFile, hint } = await startLocalStack();
375
- const lines = await afterLocalStackChange(code, wroteEnvFile);
376
- return { code, lines: hint === undefined ? lines : [hint, ...lines] };
377
- }
378
- if (command === "status") {
379
- if (connection === null || isLocalConnection(connection)) {
380
- return localStatus();
381
- }
382
- return {
383
- code: 0,
384
- lines: [
385
- `This session targets ${describeDbTarget(connection)}` +
386
- (connection.projectRef
387
- ? ` (project ${connection.projectRef}).`
388
- : ".") +
389
- " Check the Supabase dashboard for its health.",
390
- ],
391
- };
392
- }
393
- if (connection === null) {
394
- return {
395
- code: 1,
396
- lines: [`No database connection was resolved for \`${command}\`.`],
397
- };
398
- }
399
- if (command === "migrate") {
400
- return { code: await pushMigrations(connection), lines: [] };
401
- }
402
- return reset(connection);
403
- }
@@ -1,59 +0,0 @@
1
- /** The run-time `DEVTOOLS_SENTRY_DSN` if set, else the baked one. */
2
- export declare function resolveDevtoolsDsn(env: NodeJS.ProcessEnv, baked: string): string;
3
- /**
4
- * `'ci'` in every GitHub Actions job (`CI` is set by the runner itself,
5
- * before any workflow-authored env), `'local'` on a contributor's machine.
6
- * One of `@devdogsuga/telemetry`'s `ENVIRONMENTS`.
7
- */
8
- export declare function devtoolsEnvironment(): "ci" | "local";
9
- /**
10
- * `DEVTOOLS_TELEMETRY=0` (any other value, including unset, leaves reporting
11
- * on) is the only opt-out. Checked by both `initDevtoolsTelemetry` (skips
12
- * `Sentry.init` outright) and `captureDevtoolsError` (so setting it mid-run,
13
- * or between two invocations in the same process, still works).
14
- */
15
- export declare function devtoolsTelemetryEnabled(): boolean;
16
- /**
17
- * Whether anyone is actually using devtools in this process. Package-registry
18
- * scanners install every published version within minutes and run it in a
19
- * throwaway sandbox (random `DESKTOP-xxxxxx` hosts, Firecracker VMs, a fuzzer
20
- * that turns `process.exit` into a throw). Left unfiltered, each release filed
21
- * the same two issues from them. They run with no DevDogsUGA checkout and no
22
- * terminal. A person has at least one of the two (`setup` runs outside a
23
- * checkout, but in a terminal), and CI always has a checkout.
24
- */
25
- export declare function hasRealCaller(inRepo: boolean, isTTY: boolean): boolean;
26
- /**
27
- * Initializes `@sentry/node` for this CLI process. Safe to call more than
28
- * once (idempotent) and safe to call with no DSN configured (no-ops via
29
- * `buildSentryOptions`, see its header).
30
- *
31
- * `command` becomes a `command` tag on every event this process reports, so
32
- * an issue in Sentry names the subcommand it came from (`db reset`,
33
- * `deploy platform`, …) without anyone opening the job log first.
34
- */
35
- export declare function initDevtoolsTelemetry(command: string): void;
36
- /**
37
- * Reports an error nothing below the entry points caught — `launch.ts`'s
38
- * `dispatch`, `launch-ci.ts`, and the bins — then flushes before the process
39
- * exits. Node's event loop dies with `process.exit`, taking any in-flight
40
- * request to Sentry's ingest endpoint with it, so the flush must be awaited
41
- * BEFORE that call — never after.
42
- *
43
- * A short timeout: a CLI exiting on error should not hang perceptibly longer
44
- * because Sentry's ingest is slow or unreachable.
45
- */
46
- export declare function captureDevtoolsError(err: unknown): Promise<void>;
47
- /**
48
- * Reports an error a command caught and explained to the reader itself
49
- * (`explainError` in `ui.ts`, `devtools-ci deploy`'s catch), then carried on
50
- * to a normal exit. Not flushed: the SDK's in-flight request keeps the event
51
- * loop alive until it lands, so a natural exit waits for it on its own. A
52
- * path that ends in `process.exit` instead must use `captureDevtoolsError`.
53
- */
54
- export declare function reportDevtoolsError(err: unknown): void;
55
- /**
56
- * Reports a failure that has no error object — a subprocess or deploy step
57
- * that exited non-zero. Same no-flush contract as `reportDevtoolsError`.
58
- */
59
- export declare function reportDevtoolsFailure(message: string, extra?: Record<string, unknown>): void;
package/dist/tier.d.ts DELETED
@@ -1,40 +0,0 @@
1
- import type { DeployEnvironment } from "@devdogsuga/env";
2
- interface ResolveTierOptions {
3
- /** Stderr prefix, e.g. "devtools cf preview". */
4
- label?: string;
5
- /** Injectable for tests; defaults to the repo's `availableTiers()`. */
6
- available?: DeployEnvironment[];
7
- /**
8
- * The tier the process has already ENTERED, honoured when no explicit tier
9
- * was passed. Injectable for tests; defaults to `process.env.DEPLOY_ENV`.
10
- *
11
- * The wizard enters a tier once, up front (see `menu.ts`), by loading its
12
- * env and setting `DEPLOY_ENV`; a `DEPLOY_ENV=staging pnpm devtools …` on
13
- * the command line does the same. Either way a command that resolves its own
14
- * tier should use that answer rather than ask a question already settled for
15
- * the whole session.
16
- */
17
- deployEnv?: string;
18
- /** Injectable for tests; defaults to `process.stdin.isTTY`. */
19
- isTTY?: boolean;
20
- /** Injectable for tests; defaults to a clack `select` wrapped in `unwrap`. */
21
- prompt?: (message: string, choices: {
22
- value: DeployEnvironment;
23
- label: string;
24
- hint?: string;
25
- }[]) => Promise<DeployEnvironment>;
26
- }
27
- /**
28
- * The deploy tier a command runs under when `--tier` was not passed.
29
- *
30
- * Prompts ONLY when more than one deploy tier's file is present — the
31
- * handful of contributors working on the deploy workflow — so that everyone
32
- * else (just development, possibly with `.env.generated` from a running
33
- * local stack) falls straight through to development with no prompt at all.
34
- *
35
- * Returns `null` after reporting an error on stderr — an invalid `--tier`, or
36
- * an interactive pick of a tier whose file is missing — so the caller can
37
- * exit nonzero without printing a second message of its own.
38
- */
39
- export declare function resolveTier(given: string | undefined, message: string, opts?: ResolveTierOptions): Promise<DeployEnvironment | null>;
40
- export {};
package/dist/tier.js DELETED
@@ -1,96 +0,0 @@
1
- /**
2
- * The shared `--tier` resolver for the handful of commands that pick a
3
- * deploy tier of their OWN, separate from the session-wide tier
4
- * `src/launch.ts` already resolved and entered before this CLI ever runs
5
- * (see that file's header, and `@devdogsuga/env/session`, which is where
6
- * `availableTiers` and the session-wide policy now live — this module used
7
- * to carry its own copy of both, one of two the wizard's tier question also
8
- * used to keep before it moved into `launch.ts`).
9
- *
10
- * `cf preview`, `cron run` and `workflows run` still need a resolver of their
11
- * own: each names the tier something it is doing right now — running a
12
- * workflow, previewing a build — SEPARATELY from the tier the session as a
13
- * whole is running under (`process.env.DEPLOY_ENV`, honoured here as the
14
- * fallback below), and a command flag can still name a different one. All
15
- * three used to ask the same "which tier?" question with a subtly different
16
- * answer, which is what this module unified. It asks only when the answer is
17
- * not foregone: when more than one deploy tier's env file is actually
18
- * present. That is the signature of someone working on the deploy workflow
19
- * itself, who keeps `.env.staging` or `.env.production` around to test
20
- * against. Everyone else falls straight through to development, exactly as
21
- * if `--tier development` had been typed.
22
- */
23
- import { select } from "@clack/prompts";
24
- import { loadEnv, loadEnvSession } from "./repo/peers.js";
25
- import { findRepoRoot } from "./repo/root.js";
26
- import { unwrap } from "./ui.js";
27
- /**
28
- * The deploy tier a command runs under when `--tier` was not passed.
29
- *
30
- * Prompts ONLY when more than one deploy tier's file is present — the
31
- * handful of contributors working on the deploy workflow — so that everyone
32
- * else (just development, possibly with `.env.generated` from a running
33
- * local stack) falls straight through to development with no prompt at all.
34
- *
35
- * Returns `null` after reporting an error on stderr — an invalid `--tier`, or
36
- * an interactive pick of a tier whose file is missing — so the caller can
37
- * exit nonzero without printing a second message of its own.
38
- */
39
- export async function resolveTier(given, message, opts = {}) {
40
- const label = opts.label ?? "devtools";
41
- const env = await loadEnv();
42
- if (given !== undefined) {
43
- if (env.isDeployEnvironment(given))
44
- return given;
45
- process.stderr.write(`${label}: unknown tier "${given}". Expected: ${env.DEPLOY_ENVIRONMENTS.join(", ")}.\n`);
46
- return null;
47
- }
48
- // Already inside a tier? Honour it instead of prompting. An entered tier is
49
- // an answer, exactly like an explicit `--tier` above — including one whose
50
- // file is missing, which `loadEnvironment` then reports — so it is validated
51
- // for shape only, not existence, and does NOT fall through to the picker.
52
- const entered = opts.deployEnv ?? process.env.DEPLOY_ENV;
53
- if (entered !== undefined &&
54
- entered !== "" &&
55
- env.isDeployEnvironment(entered)) {
56
- return entered;
57
- }
58
- const available = opts.available ??
59
- (await (await loadEnvSession()).availableTiers(findRepoRoot()));
60
- // Zero or one tier file present: there is nothing to choose between, so
61
- // asking would be a question with one possible answer. Fall through to
62
- // whichever tier is present, or development when nothing is (a machine
63
- // that has never run `env pull` at all).
64
- if (available.length <= 1)
65
- return available[0] ?? "development";
66
- const isTTY = opts.isTTY ?? process.stdin.isTTY;
67
- if (!isTTY)
68
- return "development";
69
- const prompt = opts.prompt ??
70
- (async (msg, choices) => unwrap(await select({
71
- message: msg,
72
- options: choices,
73
- })));
74
- // Show every deploy tier, not just the present ones: clack's `select` has
75
- // no true "disabled" state, so a tier whose file is missing is shown with
76
- // a hint that says so and how to fix it, rather than removed from the list
77
- // where a contributor who expected to see "production" would wonder if
78
- // they misconfigured something.
79
- const choices = env.DEPLOY_ENVIRONMENTS.map((tier) => ({
80
- value: tier,
81
- label: tier,
82
- hint: !available.includes(tier)
83
- ? `needs env pull --target ${tier}`
84
- : tier === "development"
85
- ? "the default"
86
- : tier === "production"
87
- ? "⚠️ live data"
88
- : undefined,
89
- }));
90
- const choice = await prompt(message, choices);
91
- if (!available.includes(choice)) {
92
- process.stderr.write(`${label}: ${env.fileFor(choice)} is not present — run \`pnpm devtools env pull --target ${choice}\` first.\n`);
93
- return null;
94
- }
95
- return choice;
96
- }
package/dist/ui.d.ts DELETED
@@ -1,40 +0,0 @@
1
- export declare function bail(message?: string): never;
2
- /** Exits cleanly on Ctrl-C rather than letting a cancel symbol leak onward. */
3
- export declare function unwrap<T>(value: T | symbol): T;
4
- /**
5
- * Reports a failure with the next thing to try.
6
- *
7
- * `hints` is not decoration: for most of these failures the fix is one command,
8
- * and printing it is the difference between a contributor continuing and a
9
- * contributor asking in Discord.
10
- */
11
- export declare function explain(summary: string, detail: string, hints?: string[]): void;
12
- /**
13
- * A refusal the reader can fix themselves — a name that matches nothing, a
14
- * flag missing where there is no terminal to ask. Thrown from deep enough
15
- * that the command's catch can't tell it from a real failure any other way;
16
- * `explainError` prints it like any other error but keeps it out of Sentry.
17
- */
18
- export declare class UsageError extends Error {
19
- name: string;
20
- }
21
- /**
22
- * `explain()` for a caught error rather than a refusal: prints the same way,
23
- * with `err`'s message as the detail, and reports `err` to Sentry unless it
24
- * is a {@link UsageError}. Only failures nobody anticipated belong there.
25
- */
26
- export declare function explainError(summary: string, err: unknown, hints?: string[]): void;
27
- export declare function errorMessage(err: unknown): string;
28
- export interface CheckResult {
29
- name: string;
30
- ok: boolean;
31
- detail: string;
32
- }
33
- /**
34
- * A pass/fail list.
35
- *
36
- * Deliberately plain text rather than a box-drawing table: these lines get
37
- * pasted into Discord and GitHub issues, where anything fancier turns to
38
- * rubble.
39
- */
40
- export declare function renderChecks(checks: CheckResult[]): string;