@willbooster/wb 21.6.0 → 21.7.1

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
@@ -13,12 +13,16 @@ wb <command>
13
13
 
14
14
  Commands:
15
15
  wb buildIfNeeded Build code if changes are detected
16
- wb kill-port-if-non-ci Kill the port specified by PORT environment
17
- variable if non-CI.
16
+ wb kill-port <ports..> Kill the processes listening on the given TCP
17
+ ports
18
+ wb kill-port-if-non-ci Kill the process on the PORT environment
19
+ variable (or the auto-selection preferred port)
20
+ if non-CI.
18
21
  wb lint [files...] Lint code
19
22
  wb maintenance <action> Start or stop a lightweight maintenance page
20
23
  server.
21
24
  Example: wb maintenance start
25
+ wb open-cli <target> Open a URL or file in its default application
22
26
  wb optimizeForDockerBuild Optimize configuration when building a Docker
23
27
  image
24
28
  wb prisma Run database commands [aliases: db]
@@ -39,6 +43,7 @@ Commands:
39
43
  loaded.
40
44
  wb tc Run type checking. Environment variables are not
41
45
  loaded.
46
+ wb wait-on <resource> Wait for an HTTP(S) URL or TCP port
42
47
 
43
48
  Options:
44
49
  --cascade-env Environment (fnox profile / mise env) to load
package/bin/dotenv.js CHANGED
@@ -161,25 +161,34 @@ function readFnoxEnvironmentVariables(cwd, cascade, modeFileOverridesProcessEnv)
161
161
 
162
162
  const secrets = runFnoxExport(cwd, cascade, { quiet: false });
163
163
  if (!secrets) return {};
164
- // A key is profile-specific (and may override process.env off CI) when the profile export's
165
- // value differs from the base export's; when the base export fails, no override is applied.
166
- // The base export runs lazily, only when a process.env collision needs adjudicating.
164
+ // A key's value is profile-specific (and may override process.env off CI) under EITHER
165
+ // criterion: the `--no-defaults` export — the profile's own table without the base `[secrets]`
166
+ // — contains it, or its value differs from the base export's (which alone covers a base entry
167
+ // interpolating a profile-overridden key). Both exports run lazily, only when a process.env
168
+ // collision needs adjudicating, and a failing export disables its own criterion. Because the
169
+ // profile-only export omits the base table, fnox rejects a profile default referencing a base
170
+ // secret (forbidden by the repository rules); the warning names the rule.
171
+ let cachedProfileKeys = false;
172
+ const getProfileKeys = () => {
173
+ if (cachedProfileKeys === false) {
174
+ const profileSecrets = runFnoxExport(cwd, cascade, { quiet: false, profileOnly: true });
175
+ cachedProfileKeys = profileSecrets && new Set(Object.keys(profileSecrets));
176
+ }
177
+ return cachedProfileKeys;
178
+ };
167
179
  let cachedBaseSecrets = false;
168
- const getBaseSecrets = () => {
180
+ const overridesProcessEnv = (key, value) => {
181
+ if (getProfileKeys()?.has(key)) return true;
169
182
  if (cachedBaseSecrets === false) {
170
183
  cachedBaseSecrets = runFnoxExport(cwd, undefined, { quiet: true, ignoreProfileEnvVar: true });
171
184
  }
172
- return cachedBaseSecrets;
185
+ return cachedBaseSecrets !== undefined && cachedBaseSecrets[key] !== value;
173
186
  };
174
187
 
175
188
  const envVars = {};
176
189
  for (const [key, value] of Object.entries(secrets)) {
177
190
  if (typeof value !== 'string') continue;
178
- if (key in process.env) {
179
- const baseSecrets = modeFileOverridesProcessEnv && cascade ? getBaseSecrets() : undefined;
180
- const overridesProcessEnv = baseSecrets !== undefined && baseSecrets[key] !== value;
181
- if (!overridesProcessEnv) continue;
182
- }
191
+ if (key in process.env && !(modeFileOverridesProcessEnv && cascade && overridesProcessEnv(key, value))) continue;
183
192
  envVars[key] = value;
184
193
  }
185
194
  return envVars;
@@ -189,15 +198,18 @@ function runFnoxExport(cwd, cascade, options) {
189
198
  // `--if-missing error`: fnox otherwise exits 0 and silently omits secrets it fails to resolve.
190
199
  // `--non-interactive`: prompts or browser auth flows would hang forever because stdin is ignored.
191
200
  const args = ['export', '--format', 'json', '--no-color', '--if-missing', 'error', '--non-interactive'];
192
- const env = { ...process.env };
193
201
  if (cascade) {
194
202
  args.push('--profile', cascade);
195
203
  }
204
+ if (options.profileOnly) {
205
+ // Omit the base `[secrets]` table so the export's key set is exactly the profile's own
206
+ // declarations, giving per-key provenance regardless of whether the values coincide.
207
+ args.push('--no-defaults');
208
+ }
209
+ const env = { ...process.env };
196
210
  if (options.ignoreProfileEnvVar) {
197
- // Without `--profile`, fnox falls back to FNOX_PROFILE; the base-adjudication export must
198
- // read the BASE secrets, so the inherited profile selection is cleared for it — and only for
199
- // it. A PRIMARY export still honors FNOX_PROFILE: it either stays profile-less (fnox reads the
200
- // variable) or folds it into the `--profile` it passes (see wb dotenv's cascade).
211
+ // Without `--profile`, fnox falls back to FNOX_PROFILE; the base-adjudication export must read
212
+ // the BASE secrets, so the inherited profile selection is cleared for it — and only for it.
201
213
  delete env.FNOX_PROFILE;
202
214
  }
203
215
  const result = childProcess.spawnSync('fnox', args, {
@@ -207,9 +219,15 @@ function runFnoxExport(cwd, cascade, options) {
207
219
  stdio: ['ignore', 'pipe', 'pipe'],
208
220
  });
209
221
  if (result.error || result.status !== 0 || !result.stdout?.trim()) {
222
+ // The profile-only export reports what its failure costs plus its likeliest cause, and always
223
+ // quotes fnox's own error because other causes (e.g. a fnox too old for `--no-defaults`) look
224
+ // identical from here.
210
225
  if (!options.quiet) {
226
+ const reason = result.error?.message || result.stderr?.trim() || `fnox exited with status ${result.status}`;
211
227
  console.warn(
212
- `Failed to read fnox secrets: ${result.error?.message || result.stderr?.trim() || `fnox exited with status ${result.status}`}`
228
+ options.profileOnly
229
+ ? `Failed to read the "${cascade}" fnox profile's own secrets, so its values equal to the base values do not override the inherited environment variables. Make the defaults in [profiles.${cascade}.secrets] independent of the base [secrets] table. ${reason}`
230
+ : `Failed to read fnox secrets: ${reason}`
213
231
  );
214
232
  }
215
233
  return;