@nifrajs/env 4.0.2 → 5.1.0

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
@@ -64,7 +64,11 @@ pass the request's bindings: `defineEnv(shape, { source: env })`.
64
64
  ## Secret safety
65
65
 
66
66
  Error messages name the offending variable and the reason - **never its value** (it may be a
67
- secret). `defineEnv` returns a frozen object, so a validated config can't be mutated downstream.
67
+ secret). A BYO validator such as valibot or zod may quote the value in its message, escaped or
68
+ cut short, so when it refuses a set value `defineEnv` reports the variable as invalid without the
69
+ validator's message. For an unset variable the message is shown, since there is no value to quote.
70
+ Use the `env.*` helpers when you want the reason as well. `defineEnv` returns a frozen object, so a
71
+ validated config can't be mutated downstream.
68
72
 
69
73
  ## For AI agents
70
74
 
package/dist/define.d.ts CHANGED
@@ -32,8 +32,10 @@ export interface DefineEnvOptions {
32
32
  * ```
33
33
  *
34
34
  * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
35
- * validators (`t`, zod, valibot) work too; only the `env.*` helpers coerce from strings, so a plain
36
- * `t.number()` would see the raw string - use `env.number()` for coercion.
35
+ * validators (`t`, zod, valibot) work too, but their messages may quote the value, so a set value
36
+ * they refuse is reported as invalid without their words; an unset one shows their message. Only the
37
+ * `env.*` helpers coerce from strings, so a plain `t.number()` would see the raw string - use
38
+ * `env.number()` for coercion.
37
39
  */
38
40
  export declare function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptions): EnvResult<S>;
39
41
  //# sourceMappingURL=define.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEhE,kCAAkC;AAClC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAEvD,4EAA4E;AAC5E,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,IAAI;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAA;AAE1F,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACrD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,CA8BhG"}
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEhE,kCAAkC;AAClC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAEvD,4EAA4E;AAC5E,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,IAAI;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAA;AAE1F,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACrD;AAID;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,CAuChG"}
package/dist/define.js CHANGED
@@ -1,3 +1,4 @@
1
+ const WITHHELD = "is invalid (the validator's message is withheld, since it may quote the value)";
1
2
  /**
2
3
  * Validate the environment against a schema and return a **frozen, typed** object - or throw at
3
4
  * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails
@@ -18,8 +19,10 @@
18
19
  * ```
19
20
  *
20
21
  * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
21
- * validators (`t`, zod, valibot) work too; only the `env.*` helpers coerce from strings, so a plain
22
- * `t.number()` would see the raw string - use `env.number()` for coercion.
22
+ * validators (`t`, zod, valibot) work too, but their messages may quote the value, so a set value
23
+ * they refuse is reported as invalid without their words; an unset one shows their message. Only the
24
+ * `env.*` helpers coerce from strings, so a plain `t.number()` would see the raw string - use
25
+ * `env.number()` for coercion.
23
26
  */
24
27
  export function defineEnv(shape, options) {
25
28
  const source = options?.source ??
@@ -32,11 +35,20 @@ export function defineEnv(shape, options) {
32
35
  const result = schema["~standard"].validate(source[key]);
33
36
  if (result instanceof Promise) {
34
37
  // Env validation must be synchronous (it runs once, at import) - an async validator is a
35
- // configuration mistake, surfaced as a problem rather than an unhandled promise.
38
+ // configuration mistake, surfaced as a problem. Its promise is observed so a rejection is not
39
+ // reported as unhandled after the caller catches the refusal.
40
+ result.catch(() => { });
36
41
  problems.push(` ${key}: async validators are not supported in defineEnv`);
37
42
  continue;
38
43
  }
39
44
  if (result.issues !== undefined) {
45
+ const raw = source[key];
46
+ // Only the `env.*` helpers promise value-free messages. Another validator may quote the value
47
+ // escaped, truncated or transformed, past any search-and-replace, so its words are not shown.
48
+ if (schema["~standard"].vendor !== "nifra-env" && raw !== undefined && raw !== "") {
49
+ problems.push(` ${key}: ${WITHHELD}`);
50
+ continue;
51
+ }
40
52
  for (const i of result.issues)
41
53
  problems.push(` ${key}: ${i.message}`);
42
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,SAAS,CAAqB,KAAQ,EAAE,OAA0B;IAChF,MAAM,MAAM,GACV,OAAO,EAAE,MAAM;QACd,UAAyE,CAAC,OAAO,EAAE,GAAG;QACvF,EAAE,CAAA;IACJ,MAAM,GAAG,GAA4B,EAAE,CAAA;IACvC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAqB,CAAA;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;YAC9B,yFAAyF;YACzF,iFAAiF;YACjF,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,mDAAmD,CAAC,CAAA;YAC1E,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM;gBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;QACxE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,qCAAqC,QAAQ,CAAC,MAAM,iBAAiB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,CACrI,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAiB,CAAA;AAC3C,CAAC"}
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAgBA,MAAM,QAAQ,GAAG,gFAAgF,CAAA;AAEjG;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS,CAAqB,KAAQ,EAAE,OAA0B;IAChF,MAAM,MAAM,GACV,OAAO,EAAE,MAAM;QACd,UAAyE,CAAC,OAAO,EAAE,GAAG;QACvF,EAAE,CAAA;IACJ,MAAM,GAAG,GAA4B,EAAE,CAAA;IACvC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAqB,CAAA;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;YAC9B,yFAAyF;YACzF,8FAA8F;YAC9F,8DAA8D;YAC9D,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACtB,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,mDAAmD,CAAC,CAAA;YAC1E,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;YACvB,8FAA8F;YAC9F,8FAA8F;YAC9F,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;gBAClF,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,QAAQ,EAAE,CAAC,CAAA;gBACtC,SAAQ;YACV,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM;gBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;QACxE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,qCAAqC,QAAQ,CAAC,MAAM,iBAAiB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,CACrI,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAiB,CAAA;AAC3C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nifrajs/env",
3
- "version": "4.0.2",
3
+ "version": "5.1.0",
4
4
  "description": "Typed, validated environment variables for nifra - define a schema, get a frozen typed object, fail loud at boot listing every problem. Coercing helpers (number/port/boolean/url/enum) + any Standard Schema. Dependency-free, edge-safe.",
5
5
  "keywords": [
6
6
  "bun",
package/src/define.ts CHANGED
@@ -14,6 +14,8 @@ export interface DefineEnvOptions {
14
14
  readonly source?: Record<string, string | undefined>
15
15
  }
16
16
 
17
+ const WITHHELD = "is invalid (the validator's message is withheld, since it may quote the value)"
18
+
17
19
  /**
18
20
  * Validate the environment against a schema and return a **frozen, typed** object - or throw at
19
21
  * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails
@@ -34,8 +36,10 @@ export interface DefineEnvOptions {
34
36
  * ```
35
37
  *
36
38
  * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
37
- * validators (`t`, zod, valibot) work too; only the `env.*` helpers coerce from strings, so a plain
38
- * `t.number()` would see the raw string - use `env.number()` for coercion.
39
+ * validators (`t`, zod, valibot) work too, but their messages may quote the value, so a set value
40
+ * they refuse is reported as invalid without their words; an unset one shows their message. Only the
41
+ * `env.*` helpers coerce from strings, so a plain `t.number()` would see the raw string - use
42
+ * `env.number()` for coercion.
39
43
  */
40
44
  export function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptions): EnvResult<S> {
41
45
  const source =
@@ -50,11 +54,20 @@ export function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptio
50
54
  const result = schema["~standard"].validate(source[key])
51
55
  if (result instanceof Promise) {
52
56
  // Env validation must be synchronous (it runs once, at import) - an async validator is a
53
- // configuration mistake, surfaced as a problem rather than an unhandled promise.
57
+ // configuration mistake, surfaced as a problem. Its promise is observed so a rejection is not
58
+ // reported as unhandled after the caller catches the refusal.
59
+ result.catch(() => {})
54
60
  problems.push(` ${key}: async validators are not supported in defineEnv`)
55
61
  continue
56
62
  }
57
63
  if (result.issues !== undefined) {
64
+ const raw = source[key]
65
+ // Only the `env.*` helpers promise value-free messages. Another validator may quote the value
66
+ // escaped, truncated or transformed, past any search-and-replace, so its words are not shown.
67
+ if (schema["~standard"].vendor !== "nifra-env" && raw !== undefined && raw !== "") {
68
+ problems.push(` ${key}: ${WITHHELD}`)
69
+ continue
70
+ }
58
71
  for (const i of result.issues) problems.push(` ${key}: ${i.message}`)
59
72
  } else {
60
73
  out[key] = result.value