@devdogsuga/devtools 0.1.50 → 0.1.51-next.526

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.
package/README.md CHANGED
@@ -56,11 +56,12 @@ command path (deprecated ones marked), for tools that check what a page shows.
56
56
 
57
57
  The `db` and `cf` namespaces are gone: `supabase`, `wrangler`, `drizzle-kit`
58
58
  and `psql` plus package scripts (`types:db`, `types:drizzle`, `types:cf`,
59
- `preview`) replace them. `run` stays as a deprecated alias, hidden from the
60
- menu, for callers that have not moved yet (TASK-404 removes it); `--help` names
61
- its replacement. The retired `db`, `cf`, `gen`, `emails`, `grant-root` and
62
- `preset` names are refused with where they went (`preset apply-migrations` is
63
- now `apply-migrations`, and so on).
59
+ `preview`) replace them. The deprecated `run` alias is gone too (TASK-404):
60
+ `pnpm -r run <task>` runs a task in every package and `pnpm -F <app> <task>`
61
+ in one. The retired `db`, `cf`, `gen`, `emails`, `grant-root`, `preset` and
62
+ `run` names are refused with where they went (`preset apply-migrations` is now
63
+ `apply-migrations`, and so on). Inside a product repository (below) `db` is
64
+ the product's own command.
64
65
 
65
66
  What always needs production secrets is not here. `deploy`, `env
66
67
  pull|push|audit` and `planner` are in `@devdogsuga/backstage`
@@ -92,6 +93,79 @@ name `devdogs-monorepo` or `backstage`; the layout code is
92
93
  `pnpm exec supabase` and `wrangler` run inside DevDogsUGA's workspace, so
93
94
  `devdogsuga/` needs its own `pnpm install` before the commands that use them.
94
95
 
96
+ ## Product repositories
97
+
98
+ A repository with a `devtools.config.json` at its root is a **product** (DogDays, DogPack): devtools
99
+ reads the file and serves a smaller command set that needs no tiers, no env registry and no workspace.
100
+ DogPack has no `package.json`, so it runs the published CLI directly:
101
+
102
+ ```sh
103
+ npx @devdogsuga/devtools@next setup
104
+ ```
105
+
106
+ | Command | What it does |
107
+ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
108
+ | `setup [--local \| --hosted]` | Writes `.env` from `.env.example`; starts the Docker stack (or takes your own hosted project's URL, keys and session-pooler `DB_URL`); `db sync`; the types; then `oauth`. |
109
+ | `db sync [--rebuild] [--yes]` | Makes your development database match `supabase/schemas/`. Never resets it; `--rebuild` is the explicit reset (local only) and registers sign in again afterwards. |
110
+ | `db types [--download] [--pack <file>]` | Generates the TypeScript types or Dart models from your database, or downloads the ones CI built for your exact schema hash. `--pack` writes the release asset (CI). |
111
+ | `db hash` | Prints the schema hash that names the generated types. |
112
+ | `dev-data [--member <email\|id>]` | Runs the product's `devData.file` SQL, in one transaction, as the member who last signed in with DevDogs. Refuses the product's production project. |
113
+ | `oauth` | "Sign in with DevDogs" on your database (the same wizard as the platform's). |
114
+ | `doctor` | Docker, the pinned Supabase CLI, `.env`, the database, whether the types match the schema. |
115
+ | `supabase <args>` | The Supabase CLI at the version the product pins. |
116
+ | `check env-example` | CI: `.env.example` holds public values only (it ships in the app). |
117
+
118
+ How it works, in short:
119
+
120
+ - **Schemas, not migrations.** Contributors edit `supabase/schemas/*.sql`. `db sync` asks the Supabase CLI
121
+ (`db schema declarative sync --no-apply`) to diff them against a git-ignored `supabase/migrations/` that
122
+ records what this database has had applied, writes the difference as a new migration, and applies it
123
+ (`migration up --local`, or `db push --db-url` for a hosted project). A change that drops a table or column
124
+ needs `--yes`. It then regenerates the types (and leaves them alone when nothing changed and they are current).
125
+ On a hosted project, a machine with no record (a second laptop, a deleted `supabase/migrations/`) first
126
+ restores it from the project's own history table (`migration fetch --db-url`), so the diff is not taken
127
+ against an empty database.
128
+ - **Types are never committed.** `db types` writes them to the path in the config, which is git-ignored.
129
+ The schema hash covers the sorted schema paths, their LF-normalised contents and the generator version (the
130
+ pinned CLI, or supadart); CI uploads a `<product>-types-<hash>.tgz` asset to a rolling `generated-types`
131
+ release, and `db types --download` fetches the one for your hash. No match: it says so and points at `setup`.
132
+ - **Two env files.** `.env` is public and read by the app (`flutter run --dart-define-from-file=.env`);
133
+ `.env.tooling` is git-ignored and holds `DB_URL`, `SECRET_KEY`, the target (`local` or `hosted`) and the
134
+ "Sign in with DevDogs" client id and secret (`OAUTH_CLIENT_ID`, `OAUTH_CLIENT_SECRET`, which
135
+ `db sync --rebuild` registers again). Nothing is written to `.env.local` in a product repo. `setup` (both files) and
136
+ `oauth` (the tooling file) check that they are git-ignored and add them to the repo's `.gitignore`
137
+ when they are not (Flutter's default ignore file leaves them out).
138
+ - **The pinned CLI.** devtools finds `supabase` in `node_modules/.bin` or on PATH when its version is the
139
+ pin, and otherwise runs `npx --yes supabase@<pin>`.
140
+ - **A hosted project** needs custom OAuth providers turned on and the app's return addresses allowed.
141
+ `setup` does both through the Management API when `SUPABASE_ACCESS_TOKEN` is set, and prints the two
142
+ dashboard steps when it is not.
143
+ - **No terminal.** `setup` takes `DEVTOOLS_SUPABASE_URL`, `DEVTOOLS_SUPABASE_PUBLISHABLE_KEY`,
144
+ `DEVTOOLS_SUPABASE_SECRET_KEY` and `DEVTOOLS_DB_URL` for a hosted project, and registers sign in from
145
+ `DEVDOGS_OAUTH_CLIENT_ID` / `DEVDOGS_OAUTH_CLIENT_SECRET` instead of opening a browser.
146
+
147
+ ```jsonc
148
+ // devtools.config.json
149
+ {
150
+ "product": "dogpack", // lowercase id; names the generated-types assets
151
+ "name": "DogPack",
152
+ "supabase": {
153
+ "version": "2.117.0", // the CLI pin; part of the types hash
154
+ "schemas": ["dogpack"], // schemas the generated types cover
155
+ // "dir": "supabase"
156
+ },
157
+ "types": { "kind": "supadart", "out": "lib/generated" }, // or { "kind": "typescript", "out": "src/database.types.ts" }
158
+ "generatedTypes": { "repo": "DevDogsUGA/DogPack" }, // where `db types --download` looks
159
+ "oauth": { "redirectUris": ["dev.dogpack://login-callback"] },
160
+ "devData": { "file": "supabase/dev-data.sql" }, // reads current_setting('devtools.member_id')
161
+ "production": { "projects": ["dogpack"] }, // refs and vanity names devtools must never touch
162
+ "runHint": "flutter run --dart-define-from-file=.env",
163
+ }
164
+ ```
165
+
166
+ The code is in `src/product/`; `src/active.ts` picks the tree, and `src/launch.ts` switches to it before any
167
+ tier is resolved.
168
+
95
169
  ## Telemetry disclosure
96
170
 
97
171
  This CLI reports its own crashes to Sentry (see `src/telemetry.ts`), on by
@@ -108,10 +182,10 @@ default, in both `pnpm devtools` and `devtools-ci`:
108
182
  no `Sentry.init()` call happens: no network request, no console output.
109
183
  - **What's scrubbed**: this CLI touches local `.env` files, so every event
110
184
  passes through
111
- `@devdogsuga/telemetry`'s shared scrubbers before it leaves the process —
185
+ `@devdogsuga/sdk/telemetry`'s shared scrubbers before it leaves the process —
112
186
  file paths reduced to basenames, email addresses redacted, and
113
187
  token/secret-shaped values stripped out of messages, breadcrumbs, and
114
- stack frames. See Backstage's `packages/telemetry/src/scrub.ts` for exactly what each
188
+ stack frames. See `packages/sdk/src/telemetry/scrub.ts` for exactly what each
115
189
  scrubber matches.
116
190
 
117
191
  ## Layout
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ // The `with-env` bin: loads a tier's env files around one command.
3
+ //
4
+ // with-env [--tier <tier>] <command> [args...]
5
+ // with-env -c '<shell command>'
6
+ // with-env --worker <app> -- <command> [args...]
7
+ //
8
+ // It used to be `@devdogsuga/env`'s bin and ran TypeScript source through tsx;
9
+ // the env tooling moved into devtools, so it ships built like the other bin.
10
+ // tsx stays registered because `--worker` imports an app's TypeScript env
11
+ // manifest. A `node` shebang is what package-manager bin shims handle most
12
+ // reliably (notably the generated .cmd on Windows), and resolving tsx through
13
+ // this package's own dependencies avoids relying on it being on PATH.
14
+ import { register } from "tsx/esm/api";
15
+
16
+ register();
17
+ await import("../dist/with-env.js");
@@ -0,0 +1,38 @@
1
+ import { createRequire } from "node:module";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ //#region ../cli-core/src/env-runtime/app-registry.ts
6
+ /**
7
+ * Loads an app's own manifest so `with-env --worker` can scope the Worker env.
8
+ *
9
+ * The registry fills as a side effect of importing the manifest, and it must
10
+ * be the SAME `@devdogsuga/sdk/env` instance the manifest's `declare()` calls hit,
11
+ * which is the copy resolved from the manifest, not this package's own
12
+ * (running from source under tsx, those are different files). So the registry
13
+ * is read back from that copy.
14
+ */
15
+ /** `src/env.ts`, then `env.ts`; both present in one package is an error. */
16
+ function findManifest(dir) {
17
+ const inSrc = join(dir, "src", "env.ts");
18
+ const atRoot = join(dir, "env.ts");
19
+ if (existsSync(inSrc) && existsSync(atRoot)) throw new Error(`${dir} has BOTH src/env.ts and env.ts. One package gets one manifest.`);
20
+ return existsSync(inSrc) ? inSrc : existsSync(atRoot) ? atRoot : null;
21
+ }
22
+ /** Needs a tsx-enabled process, which the `with-env` bin always is. */
23
+ async function loadAppRegistry(dir) {
24
+ const manifest = findManifest(dir);
25
+ if (!manifest) throw new Error(`no env manifest (src/env.ts or env.ts) in ${dir}.`);
26
+ const previous = process.env.SKIP_ENV_VALIDATION;
27
+ process.env.SKIP_ENV_VALIDATION = "1";
28
+ try {
29
+ await import(pathToFileURL(manifest).href);
30
+ } finally {
31
+ if (previous === void 0) delete process.env.SKIP_ENV_VALIDATION;
32
+ else process.env.SKIP_ENV_VALIDATION = previous;
33
+ }
34
+ const resolved = createRequire(manifest).resolve("@devdogsuga/sdk/env");
35
+ return await import(pathToFileURL(resolved).href);
36
+ }
37
+ //#endregion
38
+ export { findManifest, loadAppRegistry };