@devdogsuga/devtools 0.1.50 → 0.1.51-next.527

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,357 +0,0 @@
1
- import { i as ownPackageDir } from "./root-CjPWNkBu.js";
2
- import { a as repoPeerUrl, n as loadEnv, o as resolveRepoPeerUrl, p as resolveLayout, t as getEnvSync } from "./peers-DvUH5VxX.js";
3
- import { register } from "node:module";
4
- import { existsSync, readdirSync, realpathSync } from "node:fs";
5
- import { join } from "node:path";
6
- import { pathToFileURL } from "node:url";
7
- //#region ../cli-core/src/repo/peer-redirect.ts
8
- /**
9
- * Points one module's bare import of a peer at the copy the target repo
10
- * resolved (`repo/peers.ts`).
11
- *
12
- * devtools' own `env.ts` manifest imports `@devdogsuga/env` by bare
13
- * specifier, and from an installed copy that specifier resolves relative to
14
- * the manifest's own location: inside the pnpm store, next to devtools,
15
- * where an optional peer is never installed under `pnpm dlx`. The import
16
- * failed with ERR_MODULE_NOT_FOUND, and every `env` command with it. Even
17
- * where the specifier does resolve (devtools installed as a devDependency),
18
- * the only copy that keeps the registry's module identity is the one the
19
- * repo's manifests use, so the redirect is applied whenever that copy is
20
- * known rather than only as a fallback.
21
- *
22
- * Node resolve hooks (`module.register`) rather than rewriting the file: the
23
- * manifest also imports `zod`, which has to keep resolving from devtools'
24
- * own location, and a copy written anywhere else would lose that.
25
- */
26
- /** `redirectPeer` for several at once: the hooks keep one table per
27
- * registration, so everything that needs redirecting goes in one call. */
28
- function redirectPeers(redirects) {
29
- register("./peer-redirect-hooks.js", import.meta.url, { data: redirects });
30
- }
31
- //#endregion
32
- //#region ../cli-core/src/repo/tsx-loader.ts
33
- /**
34
- * Loads the repo's own TypeScript at runtime: env manifests
35
- * (each app's `src/env.ts` and friends), cron contracts
36
- * (each app's `cloudflare/scheduled.ts`), and — via `source.ts` — the
37
- * `devdogs-source` condition packages (`open-graph`, `email`, `docs`).
38
- *
39
- * Uses `tsx`'s programmatic API (`register()` from `tsx/esm/api`), NOT the
40
- * `--conditions=devdogs-source` CLI flag the old in-repo devtools used —
41
- * this package ships built JS and runs from `dist/`, so there is no `tsx`
42
- * process wrapping it anymore (see the package README / CUTOVER note on
43
- * "built JS, tsx only for repo TS").
44
- *
45
- * Gotcha (FINDINGS.md experiments 3 and 4, gotcha C): do NOT pass a
46
- * `namespace` to `register()`. It silently breaks tsx's own relative
47
- * `./foo.js` → `./foo.ts` extension-fallback resolution for files loaded
48
- * under that registration — exactly the convention `open-graph`, `email`,
49
- * and any future `devdogs-source` package use for their internal relative
50
- * imports. `register({})` (no options) is the only form validated.
51
- */
52
- let registered = false;
53
- /** Idempotent: registers tsx's ESM loader hooks once per process. */
54
- async function ensureRegistered() {
55
- if (registered) return;
56
- const { register } = await import("tsx/esm/api");
57
- register();
58
- registered = true;
59
- }
60
- /**
61
- * Imports a repo TypeScript file at an absolute path, loaded through tsx.
62
- * Returns the module namespace, typed as `T` by the caller (there is no way
63
- * to know the shape of an arbitrary repo file's exports statically here).
64
- */
65
- async function importRepoTs(absolutePath) {
66
- await ensureRegistered();
67
- return import(pathToFileURL(absolutePath).href);
68
- }
69
- //#endregion
70
- //#region ../cli-core/src/env/discovery.ts
71
- /**
72
- * Fills the `@devdogsuga/env` registry by importing every manifest.
73
- *
74
- * The registry populates as a SIDE EFFECT of importing each manifest module.
75
- * `declare()` runs at import time, so a process that never imports them sees an
76
- * empty registry and every derived selector returns nothing. That is the
77
- * fail-open shape this module closes: anything that routes secrets calls
78
- * `loadRegistry()` first, and `assertRegistryLoaded()` is the guard the
79
- * selectors' consumers use to refuse an empty answer.
80
- *
81
- * Discovery is by filename, per the model doc: `src/env.ts`, then `env.ts`, per
82
- * workspace package. Both present is a hard error, because two manifests in one
83
- * package means two places for the next declaration to land and no rule saying
84
- * which. No `package.json` pointer: every other tool in this repo is found by
85
- * filename (`tsconfig.json`, `wrangler.jsonc`, `supadart.yaml`), and a pointer
86
- * would be the only one of its kind.
87
- *
88
- * From a Backstage checkout the scan covers BOTH repos (`repo/layout.ts`):
89
- * Backstage's `apps/*` and `packages/*`, then DevDogsUGA's through
90
- * `devdogsuga/`, de-duplicated by directory name with Backstage first.
91
- *
92
- * One special case: `supabase/env.ts` sits at DevDogsUGA's root, OUTSIDE the
93
- * workspace globs. Its variables belong to `config.toml` and the Supabase
94
- * CLI, not to any package, so it lives next to the config that reads them.
95
- *
96
- * `@devdogsuga/env` itself (the package that exports `define()`/`declare()`)
97
- * no longer needs a special-case exclusion here: since the Backstage
98
- * cutover it is an installed npm dependency, not a workspace package under
99
- * `packages/`, so this scan never sees it at all.
100
- *
101
- * devtools' OWN operator manifest (this package's root `env.ts` — the keys
102
- * no app reads at all: `BWS_ACCESS_TOKEN`, `CLOUDFLARE_API_TOKEN`, and
103
- * friends) has the same problem in reverse: since the Backstage cutover
104
- * devtools is no longer one of the TARGET repo's workspace packages either,
105
- * so the scan below would never see it. It is loaded unconditionally,
106
- * always, regardless of which repo devtools is running against — see
107
- * `ownManifestPath()`'s own comment for how it stays resolvable both from a
108
- * workspace checkout and from an installed `pnpm dlx`/`node_modules` copy,
109
- * and for why loading it through the same `importRepoTs()` tsx path as
110
- * every other manifest (rather than a plain static `import`) is what keeps
111
- * its `declare()`/`define()` calls landing in the SAME `@devdogsuga/env`
112
- * registry instance the target repo's manifests populate (module identity —
113
- * see `repo/peers.ts`'s header and the devtools-dlx prototype's
114
- * FINDINGS.md experiment 3). Its bare `@devdogsuga/env` import is
115
- * redirected to the copy `loadEnv()` resolved through the repo, because
116
- * from a `pnpm dlx` copy the specifier does not resolve at all: devtools
117
- * ships no copy of its own (`@devdogsuga/env` is only ever an optional
118
- * peer), and nothing installs one next to it. See `repo/peer-redirect.ts`.
119
- *
120
- * Most workspace packages declare nothing, so "no env.ts found" means
121
- * not-a-manifest rather than an error.
122
- *
123
- * ⚠️ A Worker still needs a manifest, even though its bindings arrive as a
124
- * function argument rather than `process.env`: a manifest is the only thing
125
- * that routes a credential to a deployed environment and the only thing that
126
- * tells `env audit` a Worker secret is supposed to be there. Without one, a
127
- * minted secret (in no Bitwarden project by design) is reported as an orphan,
128
- * i.e. as safe for the §3.6 prune path to delete.
129
- */
130
- /**
131
- * The single in-flight (or settled) load.
132
- *
133
- * Node's module cache already makes a second `import()` of the same manifest a
134
- * no-op, but memoizing the whole pass is asserted here rather than inherited: a
135
- * future bundler or test runner that re-evaluates modules would duplicate every
136
- * declaration, and duplicated declarations are what the completeness test
137
- * treats as a bug. A failed load stays failed. Every later call gets the same
138
- * rejection, because retrying into a half-populated registry would hide the
139
- * manifest that broke.
140
- */
141
- let loaded;
142
- /**
143
- * Imports every manifest so the registry populates. Idempotent; concurrent
144
- * callers share one pass. Await this before touching any derived selector.
145
- */
146
- function loadRegistry() {
147
- loaded ??= importManifests();
148
- return loaded;
149
- }
150
- /**
151
- * Refuses to proceed on an empty registry.
152
- *
153
- * For SYNC consumers of the derived selectors (`selectForPush`, `routeTo`),
154
- * which cannot await the load themselves. An empty registry makes every
155
- * selector return `[]`, and `[]` fails open in the worst direction: nothing is
156
- * never-store, so `BWS_ACCESS_TOKEN` would upload. Better a crash naming the
157
- * missing call than a push that quietly stores the unstorable.
158
- */
159
- function assertRegistryLoaded() {
160
- if (getEnvSync().variables().size === 0) throw new Error("The env registry is empty — no manifest has been imported, so the derived key sets would all be []. Await loadRegistry() (from devtools' env/discovery.ts) before routing or selecting secrets.");
161
- }
162
- async function importManifests() {
163
- await loadEnv();
164
- const redirects = [];
165
- const envUrl = repoPeerUrl("@devdogsuga/env");
166
- if (envUrl) {
167
- redirects.push({
168
- parentURL: pathToFileURL(ownManifestPath()).href,
169
- specifier: "@devdogsuga/env",
170
- url: envUrl
171
- });
172
- redirects.push(...siblingRedirects(envUrl));
173
- }
174
- if (redirects.length > 0) redirectPeers(redirects);
175
- const previous = process.env.SKIP_ENV_VALIDATION;
176
- process.env.SKIP_ENV_VALIDATION = "1";
177
- try {
178
- for (const path of manifestPaths()) try {
179
- await importRepoTs(path);
180
- } catch (cause) {
181
- throw new Error(`The env manifest at ${path} failed to import.`, { cause });
182
- }
183
- } finally {
184
- if (previous === void 0) delete process.env.SKIP_ENV_VALIDATION;
185
- else process.env.SKIP_ENV_VALIDATION = previous;
186
- }
187
- }
188
- /**
189
- * From a Backstage checkout, the manifests under `devdogsuga/` import
190
- * `@devdogsuga/env` through THAT checkout's `node_modules` (or not at all, when
191
- * it has none): a second copy of the package, and so a second registry that
192
- * every `declare()` there would populate instead of the one this process
193
- * reads. Point their imports at the copy `loadEnv()` resolved. Resolved
194
- * through `realpath`, because the loader sees the module's real location, not
195
- * the `devdogsuga` symlink.
196
- */
197
- function siblingRedirects(envUrl) {
198
- const layout = resolveLayout();
199
- if (layout.kind !== "backstage" || !layout.hasDevdogsuga) return [];
200
- const nextjs = resolveRepoPeerUrl("@devdogsuga/env/nextjs");
201
- const redirects = [];
202
- for (const path of manifestPaths()) {
203
- if (!path.startsWith(layout.devdogsugaRoot)) continue;
204
- const parentURL = pathToFileURL(realpathSync(path)).href;
205
- redirects.push({
206
- parentURL,
207
- specifier: "@devdogsuga/env",
208
- url: envUrl
209
- });
210
- if (nextjs) redirects.push({
211
- parentURL,
212
- specifier: "@devdogsuga/env/nextjs",
213
- url: nextjs
214
- });
215
- }
216
- return redirects;
217
- }
218
- /**
219
- * Every manifest file, in a stable order.
220
- *
221
- * The workspace members are enumerated by scanning `apps/*` and `packages/*`
222
- * plus the literal `docs`, a deliberately boring mirror of the three globs in
223
- * `pnpm-workspace.yaml` rather than a YAML parse: the globs have not changed
224
- * since the workspace existed, devtools carries no YAML dependency, and a new
225
- * top-level glob would already mean editing more interesting files than this
226
- * one.
227
- */
228
- function manifestPaths() {
229
- const paths = [];
230
- for (const dir of workspaceDirs()) {
231
- const manifest = manifestIn(dir);
232
- if (manifest) paths.push(manifest);
233
- }
234
- const layout = resolveLayout();
235
- const supabase = layout.hasDevdogsuga ? manifestIn(join(layout.devdogsugaRoot, "supabase")) : null;
236
- if (supabase) paths.push(supabase);
237
- paths.push(ownManifestPath());
238
- return paths;
239
- }
240
- /**
241
- * The absolute path to devtools' own `env.ts`, resolved relative to THIS
242
- * module's own file rather than the target repo — it ships alongside
243
- * `dist/` (see `package.json`'s `files`), not inside the target repo's
244
- * workspace, so `findRepoRoot()`/`workspaceDirs()` can never find it.
245
- *
246
- * The package root is `ownPackageDir()`: `env.ts` sits there, deliberately
247
- * outside `src/` (see that file's own header, and `tsconfig.typecheck.json`,
248
- * which includes it as a sibling of `src` for exactly that reason). Same file,
249
- * same relative shape, in both a workspace checkout
250
- * (`packages/devtools/env.ts`) and an installed copy
251
- * (`node_modules/@devdogsuga/devtools/env.ts`).
252
- */
253
- function ownManifestPath() {
254
- return join(ownPackageDir(), "env.ts");
255
- }
256
- /**
257
- * The CLIs' own packages: each loads its own operator manifest through
258
- * `ownManifestPath()`, so scanning them from a Backstage checkout would
259
- * declare the same keys twice.
260
- */
261
- const CLI_PACKAGES = /* @__PURE__ */ new Set(["devtools", "backstage"]);
262
- /**
263
- * `apps/*` and `packages/*` of every repo in the layout (the repo you are in
264
- * first, so it wins a name clash: before the cutover both repos carry
265
- * `apps/platform` and `packages/email`), then DevDogsUGA's `docs`.
266
- */
267
- function workspaceDirs() {
268
- const layout = resolveLayout();
269
- const roots = [layout.root];
270
- if (layout.kind === "backstage" && layout.hasDevdogsuga) roots.push(layout.devdogsugaRoot);
271
- const dirs = [];
272
- for (const parent of ["apps", "packages"]) {
273
- const found = /* @__PURE__ */ new Map();
274
- for (const root of roots) {
275
- let entries;
276
- try {
277
- entries = readdirSync(join(root, parent), { withFileTypes: true });
278
- } catch {
279
- continue;
280
- }
281
- for (const entry of entries) {
282
- if (!entry.isDirectory()) continue;
283
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
284
- if (layout.kind === "backstage" && parent === "packages" && CLI_PACKAGES.has(entry.name)) continue;
285
- if (!found.has(entry.name)) found.set(entry.name, join(root, parent, entry.name));
286
- }
287
- }
288
- for (const name of [...found.keys()].sort()) dirs.push(found.get(name));
289
- }
290
- if (layout.hasDevdogsuga) dirs.push(join(layout.devdogsugaRoot, "docs"));
291
- return dirs;
292
- }
293
- /** `src/env.ts`, then `env.ts`; both present in one package is a hard error. */
294
- function manifestIn(dir) {
295
- const inSrc = join(dir, "src", "env.ts");
296
- const atRoot = join(dir, "env.ts");
297
- const hasSrc = existsSync(inSrc);
298
- const hasRoot = existsSync(atRoot);
299
- if (hasSrc && hasRoot) throw new Error(`${dir} has BOTH src/env.ts and env.ts. One package gets one manifest — two of them means two places for the next declaration to land, and no rule saying which. Merge them.`);
300
- return hasSrc ? inSrc : hasRoot ? atRoot : null;
301
- }
302
- //#endregion
303
- //#region src/cf/local-env.ts
304
- /** The app's declared keys, deduped and sorted, from the given entries or the
305
- * loaded registry.
306
- *
307
- * `DEPLOY_ENV` and `NODE_ENV` are excluded BY NAME, not by any registry-meta
308
- * heuristic. Their committed source is wrangler.jsonc's per-env `vars` blocks
309
- * (and the framework), never an env file — see each key's `define()` doc.
310
- * Materializing them into the temp `.dev.vars` this file feeds to `wrangler
311
- * dev` lets a stray or empty `.env` value OVERRIDE the tier's wrangler var,
312
- * which surfaced as a Workflow isolate reading a blank `DEPLOY_ENV` and
313
- * throwing "has no HYPERDRIVE binding".
314
- *
315
- * A `scope: "default"` + `commented: true` filter was tried first and is
316
- * WRONG: that shape also matches `GITHUB_COMPETITION_REPO`, an opt-in
317
- * override a contributor sets deliberately in their `.env` (its wrangler
318
- * config defines no such var), and the heuristic silently stripped it from
319
- * `wrangler dev`'s environment. Wrangler-ownership is a fact about
320
- * wrangler.jsonc, not about registry metadata, so the two keys it is true
321
- * for are named outright. */
322
- const WRANGLER_OWNED_KEYS = /* @__PURE__ */ new Set(["DEPLOY_ENV", "NODE_ENV"]);
323
- async function scopedKeys(app, entries) {
324
- if (!entries) {
325
- await loadRegistry();
326
- entries = (await loadEnv()).declarations();
327
- }
328
- return [...new Set(entries.filter((entry) => entry.source === app).filter((entry) => !WRANGLER_OWNED_KEYS.has(entry.key)).map((entry) => entry.key))].sort();
329
- }
330
- /**
331
- * The process env for a `vinext dev` child, scoped the way the temp
332
- * `.dev.vars` is for `wrangler dev`.
333
- *
334
- * `@cloudflare/vite-plugin` has no `--env-file`: it reads the app dir's own
335
- * `.dev.vars`/`.env`, or — with `CLOUDFLARE_INCLUDE_PROCESS_ENV` — its whole
336
- * `process.env`, as Worker vars that override wrangler.jsonc's `vars`. So the
337
- * scoping happens on the child's env instead: every key some OTHER app
338
- * declares (and this app doesn't) is dropped, `NODE_ENV` is left to Vite, and
339
- * `DEPLOY_ENV` is pinned to the tier rather than dropped, because the Vite
340
- * process's own `next.config.ts` reads it too. Undeclared keys (PATH, HOME,
341
- * pnpm's own) stay; the child needs them and they carry no app secrets.
342
- */
343
- async function scopedProcessEnv(app, environment, tier, entries) {
344
- if (!entries) {
345
- await loadRegistry();
346
- entries = (await loadEnv()).declarations();
347
- }
348
- const own = new Set(await scopedKeys(app, entries));
349
- const scoped = { ...environment };
350
- for (const entry of entries) if (entry.source !== app && !own.has(entry.key)) delete scoped[entry.key];
351
- delete scoped.NODE_ENV;
352
- scoped.DEPLOY_ENV = tier;
353
- scoped.CLOUDFLARE_INCLUDE_PROCESS_ENV = "true";
354
- return scoped;
355
- }
356
- //#endregion
357
- export { assertRegistryLoaded as n, loadRegistry as r, scopedProcessEnv as t };
@@ -1,2 +0,0 @@
1
- import { t as scopedProcessEnv } from "./local-env-BuHU5Ckd.js";
2
- export { scopedProcessEnv };