@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
@@ -1,45 +0,0 @@
1
- /**
2
- * Zod schemas for the two cron-trigger exports an app's
3
- * `cloudflare/scheduled.ts` may declare: `CRON_ROUTES` (a schedule that fetches
4
- * one or more of the app's own routes) and the optional `WORKFLOW_CRONS`
5
- * (audit metadata for a native Cloudflare Workflow schedule).
6
- *
7
- * devtools enforces both at its import boundary (see `discovery.ts`): an app
8
- * that drifts from the shape fails the audit and a conformance test, rather
9
- * than reading as an empty (silently unaudited) map.
10
- *
11
- * Invariants, each a test rather than a hope:
12
- * - Every route starts `/` and lives on the app's own origin.
13
- * - `routes` is non-empty: a key that fires nothing is a config bug.
14
- * - `label` is non-blank: the audit's English description; never empty.
15
- * - Keyed by the cron expression exactly as wrangler carries it, so
16
- * reconciliation is a set comparison, never a parse.
17
- */
18
- import { z } from "zod";
19
- declare const CronEntry: z.ZodObject<{
20
- routes: z.ZodArray<z.ZodString>;
21
- label: z.ZodString;
22
- }, z.core.$strip>;
23
- export declare const CronRoutes: z.ZodRecord<z.ZodString, z.ZodObject<{
24
- routes: z.ZodArray<z.ZodString>;
25
- label: z.ZodString;
26
- }, z.core.$strip>>;
27
- export type CronRoutes = z.infer<typeof CronRoutes>;
28
- export type CronEntry = z.infer<typeof CronEntry>;
29
- /**
30
- * A native workflow schedule. `binding` names the Workflows binding (e.g.
31
- * `SCRAPE_WORKFLOW`); `cron list` reconciles the expression against that
32
- * binding's `workflows[].schedules` in the tier's `wrangler.jsonc`. `label` is
33
- * the audit's English description, same contract as routes.
34
- */
35
- declare const WorkflowCronEntry: z.ZodObject<{
36
- binding: z.ZodString;
37
- label: z.ZodString;
38
- }, z.core.$strip>;
39
- export declare const WorkflowCrons: z.ZodRecord<z.ZodString, z.ZodObject<{
40
- binding: z.ZodString;
41
- label: z.ZodString;
42
- }, z.core.$strip>>;
43
- export type WorkflowCrons = z.infer<typeof WorkflowCrons>;
44
- export type WorkflowCronEntry = z.infer<typeof WorkflowCronEntry>;
45
- export {};
@@ -1,35 +0,0 @@
1
- /**
2
- * Zod schemas for the two cron-trigger exports an app's
3
- * `cloudflare/scheduled.ts` may declare: `CRON_ROUTES` (a schedule that fetches
4
- * one or more of the app's own routes) and the optional `WORKFLOW_CRONS`
5
- * (audit metadata for a native Cloudflare Workflow schedule).
6
- *
7
- * devtools enforces both at its import boundary (see `discovery.ts`): an app
8
- * that drifts from the shape fails the audit and a conformance test, rather
9
- * than reading as an empty (silently unaudited) map.
10
- *
11
- * Invariants, each a test rather than a hope:
12
- * - Every route starts `/` and lives on the app's own origin.
13
- * - `routes` is non-empty: a key that fires nothing is a config bug.
14
- * - `label` is non-blank: the audit's English description; never empty.
15
- * - Keyed by the cron expression exactly as wrangler carries it, so
16
- * reconciliation is a set comparison, never a parse.
17
- */
18
- import { z } from "zod";
19
- const CronRoute = z.string().startsWith("/");
20
- const CronEntry = z.object({
21
- routes: z.array(CronRoute).min(1),
22
- label: z.string().min(1),
23
- });
24
- export const CronRoutes = z.record(z.string(), CronEntry);
25
- /**
26
- * A native workflow schedule. `binding` names the Workflows binding (e.g.
27
- * `SCRAPE_WORKFLOW`); `cron list` reconciles the expression against that
28
- * binding's `workflows[].schedules` in the tier's `wrangler.jsonc`. `label` is
29
- * the audit's English description, same contract as routes.
30
- */
31
- const WorkflowCronEntry = z.object({
32
- binding: z.string().min(1),
33
- label: z.string().min(1),
34
- });
35
- export const WorkflowCrons = z.record(z.string(), WorkflowCronEntry);
@@ -1,8 +0,0 @@
1
- /**
2
- * `config.toml` lives on a hosted project only — there is no local
3
- * `--project-ref` to push to — so this takes the ref directly rather than a
4
- * `Target`. The caller (`cli.ts`) resolves it from the tier, exactly like
5
- * every other remote db operation now does, instead of letting the supabase
6
- * CLI fall back to whatever project it has `--linked`.
7
- */
8
- export declare function runConfigPush(projectRef: string): Promise<number>;
@@ -1,11 +0,0 @@
1
- import { supabase } from "./run.js";
2
- /**
3
- * `config.toml` lives on a hosted project only — there is no local
4
- * `--project-ref` to push to — so this takes the ref directly rather than a
5
- * `Target`. The caller (`cli.ts`) resolves it from the tier, exactly like
6
- * every other remote db operation now does, instead of letting the supabase
7
- * CLI fall back to whatever project it has `--linked`.
8
- */
9
- export async function runConfigPush(projectRef) {
10
- return supabase("config", "push", "--project-ref", projectRef);
11
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Resolves the database a `db` command acts on — from the SESSION, never
3
- * from a flag.
4
- *
5
- * There used to be two connection mechanisms here (`db/remote.ts`'s
6
- * `--target remote` tier resolver, and `db/local-env.ts`'s "whatever this
7
- * process entered"), joined by a `--target local|remote` flag that asked a
8
- * question the launcher had already answered: `launch.ts` settles a session
9
- * (`--tier development:local|development:remote|staging|production`, or the
10
- * picker) and enters its env BEFORE any command dispatches, so
11
- * `process.env.DB_URL` already names the one database this session means.
12
- * This module reads that — the same `DB_URL` every app and script uses —
13
- * and every mechanism-one caller now goes through it. `resolveLocalToolingEnv`
14
- * remains for the two commands that hand a whole ENVIRONMENT to a child
15
- * process rather than needing a connection of their own.
16
- *
17
- * What it adds over a raw `process.env.DB_URL` read is the two sanity
18
- * guards a session can still violate:
19
- *
20
- * * development meaning the LOCAL stack, but `DB_URL` pointing somewhere
21
- * that is not loopback — the stack went down after launch (the overlay
22
- * is applied at entry; see `load.ts`'s probe table) or the degraded
23
- * `db`-exempt entry ran without it. Refused with `db start`
24
- * troubleshooting rather than letting `.env`'s hosted `DB_URL` answer
25
- * for a command that asked for Docker.
26
- * * a DEPLOYED tier whose `DB_URL` points AT loopback — the signature of
27
- * inherited development values winning under `override: false` (see
28
- * `launch.ts`). Refused rather than "migrating staging" against a local
29
- * container.
30
- *
31
- * Reports the reason on stderr and returns `null` on every failure path —
32
- * never throws for an expected failure — so a caller can stop without
33
- * printing a second explanation of its own.
34
- *
35
- * ## `db connect` — plausibly vestigial
36
- *
37
- * `connectRemoteProject` (`stack.ts`) still runs `supabase link
38
- * --project-ref <ref>`, the pre-session way of naming "the remote project",
39
- * remembered by the supabase CLI on disk and read by nothing in this CLI:
40
- * every operation here passes `--db-url`/`--project-ref` explicitly. It may
41
- * still matter to someone driving the bare `supabase` CLI by hand, so
42
- * removing it is a separate decision from this refactor.
43
- */
44
- import type { DeployEnvironment } from "@devdogsuga/env";
45
- import type { DevDatabase } from "@devdogsuga/env/load";
46
- export declare function isLocalDbUrl(url: string): boolean;
47
- /** The hostname for messages — never the URL itself, which carries the
48
- * password. */
49
- export declare function dbHost(url: string): string;
50
- /** What the session resolved to: the one database every `db` data command
51
- * in this process acts on. `projectRef` is only validated where it is
52
- * actually needed (`seed buckets`, `config push`). */
53
- export interface DbConnection {
54
- tier: DeployEnvironment;
55
- /** The session's development qualifier, when one was entered. */
56
- devDatabase: DevDatabase | undefined;
57
- dbUrl: string;
58
- projectRef: string | undefined;
59
- }
60
- /** Whether this connection is the Docker stack on this machine — the one
61
- * database whose erasure is routine rather than gated sternly. */
62
- export declare function isLocalConnection(conn: DbConnection): boolean;
63
- /**
64
- * How gates and reports name the target. Deliberately tier-and-host only —
65
- * never the DB_URL, which carries the password — and "remote development"
66
- * is spelled out because `staging`/`production` are also remote: the whole
67
- * reason the session vocabulary qualifies development.
68
- */
69
- export declare function describeDbTarget(conn: DbConnection): string;
70
- export interface ResolveDbConnectionOptions {
71
- /** Stderr prefix, e.g. "devtools db reset". */
72
- label?: string;
73
- /** Injectable for tests; defaults to `process.env`. */
74
- env?: NodeJS.ProcessEnv;
75
- /** Suppress the stderr reason — for callers like `db status` that treat
76
- * "no resolvable database" as an answer, not a failure. */
77
- quiet?: boolean;
78
- }
79
- export declare function resolveDbConnection(opts?: ResolveDbConnectionOptions): Promise<DbConnection | null>;
@@ -1,114 +0,0 @@
1
- import { loadEnv, loadEnvLoad } from "../repo/peers.js";
2
- /**
3
- * Hostnames that mean "the Docker stack on this machine". The same list
4
- * `docs/index-pages.ts` keeps for its delete-acknowledgment; duplicated
5
- * because that module answers a different question ("may I delete rows
6
- * here without --target remote?") and coupling the two would let a change
7
- * for one silently reshape the other.
8
- */
9
- const LOCAL_DB_HOSTS = [
10
- "localhost",
11
- "127.0.0.1",
12
- "[::1]",
13
- "host.docker.internal",
14
- ];
15
- export function isLocalDbUrl(url) {
16
- try {
17
- return LOCAL_DB_HOSTS.includes(new URL(url).hostname);
18
- }
19
- catch {
20
- return false;
21
- }
22
- }
23
- /** The hostname for messages — never the URL itself, which carries the
24
- * password. */
25
- export function dbHost(url) {
26
- try {
27
- return new URL(url).hostname || "unknown host";
28
- }
29
- catch {
30
- return "unknown host";
31
- }
32
- }
33
- /** Whether this connection is the Docker stack on this machine — the one
34
- * database whose erasure is routine rather than gated sternly. */
35
- export function isLocalConnection(conn) {
36
- return conn.tier === "development" && isLocalDbUrl(conn.dbUrl);
37
- }
38
- /**
39
- * How gates and reports name the target. Deliberately tier-and-host only —
40
- * never the DB_URL, which carries the password — and "remote development"
41
- * is spelled out because `staging`/`production` are also remote: the whole
42
- * reason the session vocabulary qualifies development.
43
- */
44
- export function describeDbTarget(conn) {
45
- if (conn.tier !== "development")
46
- return `the ${conn.tier} database`;
47
- if (isLocalDbUrl(conn.dbUrl))
48
- return "your local database";
49
- return `the remote development database at ${dbHost(conn.dbUrl)}`;
50
- }
51
- export async function resolveDbConnection(opts = {}) {
52
- const { DEPLOY_ENVIRONMENTS, fileFor, isDeployEnvironment } = await loadEnv();
53
- const { DEV_DB_ENV, isDevDatabase } = await loadEnvLoad();
54
- const env = opts.env ?? process.env;
55
- const label = opts.label ?? "devtools db";
56
- const report = (message) => {
57
- if (!opts.quiet)
58
- process.stderr.write(message);
59
- };
60
- const rawTier = env.DEPLOY_ENV;
61
- let tier;
62
- if (rawTier === undefined || rawTier === "") {
63
- tier = "development";
64
- }
65
- else if (isDeployEnvironment(rawTier)) {
66
- tier = rawTier;
67
- }
68
- else {
69
- report(`${label}: DEPLOY_ENV="${rawTier}" is not one of ${DEPLOY_ENVIRONMENTS.join(", ")}.\n`);
70
- return null;
71
- }
72
- let devDatabase;
73
- const rawDevDb = env[DEV_DB_ENV];
74
- if (tier === "development" && rawDevDb !== undefined && rawDevDb !== "") {
75
- if (!isDevDatabase(rawDevDb)) {
76
- report(`${label}: ${DEV_DB_ENV}="${rawDevDb}" is not one of: local, remote.\n`);
77
- return null;
78
- }
79
- devDatabase = rawDevDb;
80
- }
81
- const dbUrl = env.DB_URL;
82
- if (dbUrl === undefined || dbUrl === "") {
83
- if (tier !== "development") {
84
- report(`${label}: ${fileFor(tier)} has no DB_URL.\n`);
85
- }
86
- else if (devDatabase === "remote") {
87
- report(`${label}: this session targets the remote development database, but .env has no DB_URL.\n`);
88
- }
89
- else {
90
- report(`${label}: no DB_URL in this session — the local Supabase stack is ` +
91
- "not running. Run `pnpm devtools db start`, or relaunch with " +
92
- "`--tier development:remote` (or staging/production) to act on a " +
93
- "hosted database.\n");
94
- }
95
- return null;
96
- }
97
- if (tier === "development" &&
98
- devDatabase !== "remote" &&
99
- !isLocalDbUrl(dbUrl)) {
100
- report(`${label}: DB_URL points at ${dbHost(dbUrl)}, not the local stack — ` +
101
- "it is offline (or .env.generated is stale). Run `pnpm devtools db " +
102
- "start`, or relaunch with `--tier development:remote` if you mean " +
103
- "that database.\n");
104
- return null;
105
- }
106
- if (tier !== "development" && isLocalDbUrl(dbUrl)) {
107
- report(`${label}: the session tier is ${tier} but DB_URL points at ` +
108
- `${dbHost(dbUrl)} — a local address, the signature of inherited ` +
109
- "development values. Relaunch with `pnpm devtools --tier " +
110
- `${tier}\` from a clean shell.\n`);
111
- return null;
112
- }
113
- return { tier, devDatabase, dbUrl, projectRef: env.PROJECT_REF };
114
- }
package/dist/db/exec.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function runDbExec(args: string[]): Promise<number>;
package/dist/db/exec.js DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * `db exec -- <args…>` — the escape hatch.
3
- *
4
- * Everything after `--` passes straight to the Supabase CLI, unmodified. Same
5
- * stance as `bw` and `cf exec`: the wrapped CLI owns its own targeting and its
6
- * own flags, so this declares no subcommands and does no parsing of its own.
7
- */
8
- import { supabase } from "./run.js";
9
- export async function runDbExec(args) {
10
- return supabase(...args);
11
- }
@@ -1 +0,0 @@
1
- export declare function runGenerateTypes(dbUrl: string): Promise<number>;
@@ -1,4 +0,0 @@
1
- import { generateTypes } from "./run.js";
2
- export async function runGenerateTypes(dbUrl) {
3
- return generateTypes(dbUrl);
4
- }
@@ -1,69 +0,0 @@
1
- import type { DeployEnvironment } from "@devdogsuga/env";
2
- import type { DevDatabase } from "@devdogsuga/env/load";
3
- export interface EnsureGeneratedEnvDeps {
4
- /** Is anything listening on the local stack port? Injected so tests never
5
- * open a real socket. */
6
- probeLocalStack: () => boolean | Promise<boolean>;
7
- /** File existence, relative to `repoRoot`. Injected so tests never touch
8
- * a real filesystem. */
9
- exists: (file: string) => boolean;
10
- /** `supabase status -o env`'s stdout, or a rejection when the CLI fails —
11
- * most commonly because the stack on 54321 belongs to a different
12
- * project. Injected so tests never spawn the real CLI. */
13
- captureStatus: () => Promise<string>;
14
- /** Writes `.env.generated`'s full path. Injected so tests never touch a
15
- * real filesystem. */
16
- write: (path: string, contents: string) => Promise<void>;
17
- /** `docker ps --format '{{.Names}}'`, pre-split — or `null` when Docker
18
- * could not be read. Injected so tests never spawn a real subprocess. */
19
- listContainerNames: () => string[] | null;
20
- /** This checkout's own `project_id`, or `null` if unreadable. Injected so
21
- * tests never touch a real filesystem. */
22
- projectId: () => string | null;
23
- /** Used only to build the path `write` receives. */
24
- repoRoot: string;
25
- }
26
- export type EnsureGeneratedEnvResult = {
27
- outcome: "skipped";
28
- } | {
29
- outcome: "wrote";
30
- line: string;
31
- } | {
32
- outcome: "foreign";
33
- projectId: string;
34
- line: string;
35
- } | {
36
- outcome: "unreachable";
37
- };
38
- /**
39
- * Regenerates `.env.generated` from a running local stack when THIS
40
- * checkout's own copy is missing.
41
- *
42
- * A no-op (`"skipped"`) unless every one of these holds: `tier` is
43
- * `"development"`, `devDatabase` is not `"remote"` (an explicit `"local"`
44
- * or the probe-decides `undefined` both qualify), the file is genuinely
45
- * absent, and something answers the local stack's port. That last check
46
- * also covers "the file is missing because the stack is genuinely down" —
47
- * nothing here runs `supabase status` against a stack that is not there;
48
- * the existing `LocalStackOfflineError`/warning handling covers that case
49
- * exactly as before.
50
- *
51
- * `"foreign"` and `"unreachable"` both mean `supabase status -o env`
52
- * itself failed — the port answered, but the CLI could not produce a
53
- * connection block. `"foreign"` is the case a running Docker container's
54
- * name resolves to: another project's stack holds the port.
55
- * `"unreachable"` is everything else (an unreadable `config.toml`, an
56
- * unreadable `docker ps`, a container name that matches nobody) — the
57
- * caller falls through to its existing offline handling either way, since
58
- * `.env.generated` is still missing on disk.
59
- */
60
- export declare function ensureGeneratedEnvFile(tier: DeployEnvironment, devDatabase: DevDatabase | undefined, deps: EnsureGeneratedEnvDeps): Promise<EnsureGeneratedEnvResult>;
61
- /**
62
- * The production wiring for `EnsureGeneratedEnvDeps`, shared by
63
- * `../env-entry.ts` (via `realEnvEntryDeps`) and `../stack.ts`'s `db
64
- * status`. `probeLocalStack` is passed in rather than resolved here because
65
- * both callers already hold the loaded `@devdogsuga/env/load` peer their
66
- * own dispatch needs anyway — resolving it again here would mean two
67
- * different copies of the same optional peer in play.
68
- */
69
- export declare function realEnsureGeneratedEnvDeps(probeLocalStack: () => boolean | Promise<boolean>): EnsureGeneratedEnvDeps;
@@ -1,113 +0,0 @@
1
- /**
2
- * Regenerating `.env.generated` from a Supabase stack that is ALREADY
3
- * running — started by `db start` in THIS checkout, sure, but just as
4
- * often by another workspace (a different clone or worktree of the
5
- * DevDogsUGA repo) that shares this repo's `project_id`. `supabase status`
6
- * finds containers by project id, not by which checkout ran `db start`, so
7
- * a stack a sibling workspace brought up answers for THIS checkout too —
8
- * except `.env.generated` (the connection block `startLocalStack`,
9
- * `../stack.ts`, writes) only ever lands in the workspace that actually ran
10
- * it. Left alone, this checkout sees port 54321 listening with the file
11
- * missing, and `@devdogsuga/env/load`'s `selectEnvFiles` either warns (an
12
- * unqualified session) or throws `LocalStackOfflineError` (an explicit
13
- * `development:local` one) — both of which used to mean the contributor
14
- * ran `supabase status -o env > .env.generated` by hand.
15
- *
16
- * `ensureGeneratedEnvFile` does that automatically, before a session's env
17
- * files ever load: `enterSessionEnvironment` (`../env-entry.ts`) calls it on
18
- * every command dispatch, and `db status` (`../stack.ts`) calls it to
19
- * report the file's state accurately instead of trusting a stale absence.
20
- * Both are read-only from THIS checkout's point of view — nothing here
21
- * starts, stops, or resets anything; it only reads a port, a file, and
22
- * (best-effort) the stack's own connection block.
23
- *
24
- * The other failure this covers: `supabase status -o env` itself fails
25
- * because what is listening on 54321 belongs to a DIFFERENT Supabase
26
- * project — a stack this repo's own `project_id` rename left orphaned, or
27
- * an unrelated project entirely. That is reported (`"foreign"`) rather than
28
- * silently falling through to the existing offline handling, which would
29
- * otherwise just repeat "nothing is listening" advice for a port that very
30
- * much has something listening on it.
31
- */
32
- import { existsSync } from "node:fs";
33
- import { writeFile } from "node:fs/promises";
34
- import { join } from "node:path";
35
- import { supabaseCapture } from "./run.js";
36
- import { findRepoRoot } from "../repo/root.js";
37
- import { foreignStackMessage, foreignStackProjectId, listContainerNames, STACK_API_PORT, readProjectId, } from "../repo/supabase-project.js";
38
- /** The file this module writes and checks — see `@devdogsuga/env/load`'s
39
- * `GENERATED_FILE`, duplicated as a literal rather than imported so this
40
- * module never has to load the `@devdogsuga/env` peer just for one
41
- * constant. Keep in sync if that constant's value ever changes. */
42
- const GENERATED_FILE = ".env.generated";
43
- /**
44
- * Regenerates `.env.generated` from a running local stack when THIS
45
- * checkout's own copy is missing.
46
- *
47
- * A no-op (`"skipped"`) unless every one of these holds: `tier` is
48
- * `"development"`, `devDatabase` is not `"remote"` (an explicit `"local"`
49
- * or the probe-decides `undefined` both qualify), the file is genuinely
50
- * absent, and something answers the local stack's port. That last check
51
- * also covers "the file is missing because the stack is genuinely down" —
52
- * nothing here runs `supabase status` against a stack that is not there;
53
- * the existing `LocalStackOfflineError`/warning handling covers that case
54
- * exactly as before.
55
- *
56
- * `"foreign"` and `"unreachable"` both mean `supabase status -o env`
57
- * itself failed — the port answered, but the CLI could not produce a
58
- * connection block. `"foreign"` is the case a running Docker container's
59
- * name resolves to: another project's stack holds the port.
60
- * `"unreachable"` is everything else (an unreadable `config.toml`, an
61
- * unreadable `docker ps`, a container name that matches nobody) — the
62
- * caller falls through to its existing offline handling either way, since
63
- * `.env.generated` is still missing on disk.
64
- */
65
- export async function ensureGeneratedEnvFile(tier, devDatabase, deps) {
66
- if (tier !== "development" || devDatabase === "remote") {
67
- return { outcome: "skipped" };
68
- }
69
- if (deps.exists(GENERATED_FILE))
70
- return { outcome: "skipped" };
71
- if (!(await deps.probeLocalStack()))
72
- return { outcome: "skipped" };
73
- try {
74
- const env = await deps.captureStatus();
75
- await deps.write(join(deps.repoRoot, GENERATED_FILE), env);
76
- return {
77
- outcome: "wrote",
78
- line: "devtools: wrote .env.generated from the running local stack",
79
- };
80
- }
81
- catch {
82
- const names = deps.listContainerNames();
83
- const foreign = names === null ? null : foreignStackProjectId(names, deps.projectId());
84
- if (foreign !== null) {
85
- return {
86
- outcome: "foreign",
87
- projectId: foreign,
88
- line: `devtools: ${foreignStackMessage(foreign)}`,
89
- };
90
- }
91
- return { outcome: "unreachable" };
92
- }
93
- }
94
- /**
95
- * The production wiring for `EnsureGeneratedEnvDeps`, shared by
96
- * `../env-entry.ts` (via `realEnvEntryDeps`) and `../stack.ts`'s `db
97
- * status`. `probeLocalStack` is passed in rather than resolved here because
98
- * both callers already hold the loaded `@devdogsuga/env/load` peer their
99
- * own dispatch needs anyway — resolving it again here would mean two
100
- * different copies of the same optional peer in play.
101
- */
102
- export function realEnsureGeneratedEnvDeps(probeLocalStack) {
103
- const repoRoot = findRepoRoot();
104
- return {
105
- probeLocalStack,
106
- exists: (file) => existsSync(join(repoRoot, file)),
107
- captureStatus: () => supabaseCapture("status", "-o", "env"),
108
- write: (path, contents) => writeFile(path, contents),
109
- listContainerNames: () => listContainerNames(STACK_API_PORT),
110
- projectId: () => readProjectId(repoRoot),
111
- repoRoot,
112
- };
113
- }
@@ -1 +0,0 @@
1
- export declare function runIntrospect(app?: string): Promise<number>;
@@ -1,122 +0,0 @@
1
- /**
2
- * `db introspect --app <slug>` — pull an app's live schema into its generated
3
- * Drizzle files, then apply post-pull fixups.
4
- *
5
- * Replicates the old `db:pull` package script chain:
6
- * 1. drizzle-kit pull --config drizzle-introspection.config.ts (auth/storage schemas)
7
- * 2. drizzle-kit pull --config drizzle.config.ts (platform schema)
8
- * 3. Post-pull fixups on the generated schema.ts:
9
- * a. Delete relations.ts (we maintain hand-written relations)
10
- * b. Re-inject the cross-schema FK-target import (auth.users etc.)
11
- * c. Append InPlatform-suffix aliases so existing imports stay stable
12
- *
13
- * `DB_URL` comes from `resolveLocalToolingEnv` — the tier this process
14
- * already entered (`launch.ts`, before `cli.ts` ever dispatched this
15
- * command), `.env.generated` overlay included — and is injected into the
16
- * subprocess environment. See `db/local-env.ts`'s header for why this is
17
- * NOT a raw `.env` parse.
18
- */
19
- import { spawn } from "node:child_process";
20
- import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
21
- import { join } from "node:path";
22
- import { findRepoRoot } from "../repo/root.js";
23
- import { resolveLocalToolingEnv } from "./local-env.js";
24
- const APP_CONFIGS = {
25
- platform: {
26
- configs: ["drizzle-introspection.config.ts", "drizzle.config.ts"],
27
- schemaFile: "src/server/db/schema/generated/schema.ts",
28
- schemaSuffix: "InPlatform",
29
- crossSchemaImport: 'import { usersInAuth as users, oauthClientsInAuth as oauthClients } from "~/supabase/drizzle/schema"',
30
- },
31
- "schedule-builder": {
32
- configs: ["drizzle-introspection.config.ts", "drizzle.config.ts"],
33
- schemaFile: "src/server/db/schema/generated/schema.ts",
34
- schemaSuffix: "InScheduleBuilder",
35
- // schedule_builder's own tables carry no foreign keys into another
36
- // schema (its `userId` columns are bare uuids, not FK-constrained to
37
- // auth.users), so there is nothing to re-inject here.
38
- crossSchemaImport: null,
39
- },
40
- };
41
- // ── drizzle-kit pull ──────────────────────────────────────────────────────────
42
- function runDrizzlePull(appDir, configFile, env) {
43
- return new Promise((resolve) => {
44
- const child = spawn("pnpm", ["exec", "drizzle-kit", "pull", "--config", configFile], { stdio: "inherit", cwd: appDir, env });
45
- child.on("exit", (code) => resolve(code ?? 1));
46
- });
47
- }
48
- // ── Post-pull fixups ──────────────────────────────────────────────────────────
49
- function applyPostPullFixups(appDir, cfg) {
50
- const schemaPath = join(appDir, cfg.schemaFile);
51
- const relationsPath = join(appDir, cfg.schemaFile.replace("schema.ts", "relations.ts"));
52
- // 1. Delete relations.ts
53
- if (existsSync(relationsPath))
54
- rmSync(relationsPath);
55
- if (!existsSync(schemaPath))
56
- return;
57
- let src = readFileSync(schemaPath, "utf8");
58
- // 2. Re-inject cross-schema FK-target import (idempotent)
59
- const IMPORT_MARKER = "// Cross-schema FK targets";
60
- if (cfg.crossSchemaImport && !src.includes(IMPORT_MARKER)) {
61
- const lines = src.split("\n");
62
- let insertAt = 0;
63
- for (let i = 0; i < lines.length; i++) {
64
- const line = lines[i] ?? "";
65
- if (line.startsWith("import ") && line.includes("drizzle-orm")) {
66
- insertAt = i + 1;
67
- }
68
- else if (line.trim() !== "" && !line.startsWith("import ")) {
69
- break;
70
- }
71
- }
72
- lines.splice(insertAt, 0, `${IMPORT_MARKER} — re-injected by devtools db introspect after each drizzle-kit pull`, cfg.crossSchemaImport);
73
- src = lines.join("\n");
74
- }
75
- // 3. Append base-name aliases for every `<name><suffix>` export (idempotent)
76
- const ALIAS_MARKER = "// Schema-suffix aliases";
77
- if (cfg.schemaSuffix && !src.includes(ALIAS_MARKER)) {
78
- const names = new Set();
79
- const re = new RegExp(`export const (\\w+)${cfg.schemaSuffix}\\b`, "g");
80
- for (const m of src.matchAll(re))
81
- if (m[1])
82
- names.add(m[1]);
83
- if (names.size > 0) {
84
- const aliases = [...names]
85
- .sort()
86
- .map((n) => `export { ${n}${cfg.schemaSuffix} as ${n} };`)
87
- .join("\n");
88
- src = `${src.trimEnd()}\n\n${ALIAS_MARKER} — appended by devtools db introspect\n${aliases}\n`;
89
- }
90
- }
91
- writeFileSync(schemaPath, src);
92
- process.stdout.write(`[introspect] patched ${cfg.schemaFile}\n`);
93
- }
94
- // ── Entry ─────────────────────────────────────────────────────────────────────
95
- export async function runIntrospect(app) {
96
- if (!app) {
97
- process.stderr.write("devtools db introspect: --app <slug> is required.\n");
98
- return 1;
99
- }
100
- const cfg = APP_CONFIGS[app];
101
- if (!cfg) {
102
- const valid = Object.keys(APP_CONFIGS).join(", ");
103
- process.stderr.write(`devtools db introspect: unknown app "${app}". Expected: ${valid}.\n`);
104
- return 1;
105
- }
106
- const appDir = join(findRepoRoot(), "apps", app);
107
- const env = await resolveLocalToolingEnv();
108
- if (!env["DB_URL"]) {
109
- process.stderr.write("devtools db introspect: DB_URL is not set. Run " +
110
- "`pnpm devtools db start` first (for local — its connection string " +
111
- "lives in .env.generated once the stack is up), or set DB_URL in " +
112
- "the deploy tier's env file this process entered.\n");
113
- return 1;
114
- }
115
- for (const configFile of cfg.configs) {
116
- const code = await runDrizzlePull(appDir, configFile, env);
117
- if (code !== 0)
118
- return code;
119
- }
120
- applyPostPullFixups(appDir, cfg);
121
- return 0;
122
- }