@nifrajs/env 2.2.0 → 2.4.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
@@ -1,12 +1,12 @@
1
1
  # @nifrajs/env
2
2
 
3
3
  Typed, validated environment variables. Define a schema once at startup; get a **frozen, typed**
4
- object — or a **loud boot-time failure listing every problem at once**, so a misconfigured deploy
4
+ object - or a **loud boot-time failure listing every problem at once**, so a misconfigured deploy
5
5
  fails immediately instead of erroring on the first request that touches a bad var. The config half
6
6
  of nifra's "validate at every boundary" rule. Dependency-free, edge-safe.
7
7
 
8
8
  ```ts
9
- // env.ts — imported once at startup
9
+ // env.ts - imported once at startup
10
10
  import { defineEnv, env } from "@nifrajs/env"
11
11
 
12
12
  export const ENV = defineEnv({
@@ -27,7 +27,7 @@ export const ENV = defineEnv({
27
27
  A missing/invalid var fails at import:
28
28
 
29
29
  ```
30
- [nifra/env] invalid environment — 2 problem(s):
30
+ [nifra/env] invalid environment - 2 problem(s):
31
31
  DATABASE_URL: must be a valid URL
32
32
  STRIPE_SECRET: is required
33
33
 
@@ -42,7 +42,7 @@ Every value in `process.env` is a `string | undefined`; these turn it into the v
42
42
  | --- | --- | --- |
43
43
  | `env.string({ default?, optional? })` | `string` | empty string counts as unset |
44
44
  | `env.number({ default?, optional? })` | `number` | finite, coerced |
45
- | `env.port({ default? })` | `number` | integer 1–65535 |
45
+ | `env.port({ default? })` | `number` | integer 1-65535 |
46
46
  | `env.boolean({ default? })` | `boolean` | `true`/`1`/`yes`/`on` vs `false`/`0`/`no`/`off`/empty |
47
47
  | `env.enum([...], { default? })` | union | one of the listed values |
48
48
  | `env.url({ default?, optional? })` | `string` | parses with WHATWG `URL`, returns the normalized href |
@@ -52,23 +52,23 @@ Every value in `process.env` is a `string | undefined`; these turn it into the v
52
52
  ## Bring your own validator
53
53
 
54
54
  `defineEnv` accepts **any Standard Schema** (`t` from `@nifrajs/schema`, zod, valibot), not just the
55
- `env.*` helpers — handy for a shape the helpers don't cover. Only the `env.*` helpers coerce from
55
+ `env.*` helpers - handy for a shape the helpers don't cover. Only the `env.*` helpers coerce from
56
56
  strings, though: a plain `t.number()` would see the raw string, so reach for `env.number()` when you
57
57
  need coercion.
58
58
 
59
59
  ## Edge runtimes
60
60
 
61
- `defineEnv` reads `process.env` by default (Bun/Node). Cloudflare Workers has no `process.env` —
61
+ `defineEnv` reads `process.env` by default (Bun/Node). Cloudflare Workers has no `process.env` -
62
62
  pass the request's bindings: `defineEnv(shape, { source: env })`.
63
63
 
64
64
  ## Secret safety
65
65
 
66
- Error messages name the offending variable and the reason — **never its value** (it may be a
66
+ Error messages name the offending variable and the reason - **never its value** (it may be a
67
67
  secret). `defineEnv` returns a frozen object, so a validated config can't be mutated downstream.
68
68
 
69
69
  ## For AI agents
70
70
 
71
- Start with [`LLM.md`](./LLM.md) — this package's contract card (the exports you call + its footguns),
71
+ Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
72
72
  one cheap read instead of the whole corpus. For the wider framework: the repo's
73
73
  [`AGENTS.md`](../../AGENTS.md) is the copy-paste quick reference, and
74
74
  [`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
package/dist/define.d.ts CHANGED
@@ -1,25 +1,25 @@
1
1
  import type { InferOutput, StandardSchemaV1 } from "./schema.js";
2
2
  /** A schema per variable name. */
3
3
  export type EnvShape = Record<string, StandardSchemaV1>;
4
- /** The frozen, validated result — each key typed by its schema's output. */
4
+ /** The frozen, validated result - each key typed by its schema's output. */
5
5
  export type EnvResult<S extends EnvShape> = {
6
6
  readonly [K in keyof S]: InferOutput<S[K]>;
7
7
  };
8
8
  export interface DefineEnvOptions {
9
9
  /**
10
10
  * Where to read variables from. Defaults to `process.env` (Bun/Node). On Cloudflare Workers there
11
- * is no `process.env` — pass the request's `env` bindings: `defineEnv(shape, { source: env })`.
11
+ * is no `process.env` - pass the request's `env` bindings: `defineEnv(shape, { source: env })`.
12
12
  */
13
13
  readonly source?: Record<string, string | undefined>;
14
14
  }
15
15
  /**
16
- * Validate the environment against a schema and return a **frozen, typed** object — or throw at
16
+ * Validate the environment against a schema and return a **frozen, typed** object - or throw at
17
17
  * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails
18
18
  * loud and immediately instead of erroring on the first request that touches a bad var. This is the
19
19
  * boot-time half of nifra's "validate at every boundary" rule, for config.
20
20
  *
21
21
  * ```ts
22
- * // env.ts — imported once at startup
22
+ * // env.ts - imported once at startup
23
23
  * import { defineEnv, env } from "@nifrajs/env"
24
24
  * export const ENV = defineEnv({
25
25
  * DATABASE_URL: env.url(),
@@ -31,9 +31,9 @@ export interface DefineEnvOptions {
31
31
  * // ENV.PORT: number, ENV.NODE_ENV: "development" | "production" | "test", … all validated.
32
32
  * ```
33
33
  *
34
- * Errors name the offending variable and the reason — never its value (it may be a secret). BYO
34
+ * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
35
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.
36
+ * `t.number()` would see the raw string - use `env.number()` for coercion.
37
37
  */
38
38
  export declare function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptions): EnvResult<S>;
39
39
  //# sourceMappingURL=define.d.ts.map
package/dist/define.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Validate the environment against a schema and return a **frozen, typed** object — or throw at
2
+ * Validate the environment against a schema and return a **frozen, typed** object - or throw at
3
3
  * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails
4
4
  * loud and immediately instead of erroring on the first request that touches a bad var. This is the
5
5
  * boot-time half of nifra's "validate at every boundary" rule, for config.
6
6
  *
7
7
  * ```ts
8
- * // env.ts — imported once at startup
8
+ * // env.ts - imported once at startup
9
9
  * import { defineEnv, env } from "@nifrajs/env"
10
10
  * export const ENV = defineEnv({
11
11
  * DATABASE_URL: env.url(),
@@ -17,9 +17,9 @@
17
17
  * // ENV.PORT: number, ENV.NODE_ENV: "development" | "production" | "test", … all validated.
18
18
  * ```
19
19
  *
20
- * Errors name the offending variable and the reason — never its value (it may be a secret). BYO
20
+ * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
21
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
+ * `t.number()` would see the raw string - use `env.number()` for coercion.
23
23
  */
24
24
  export function defineEnv(shape, options) {
25
25
  const source = options?.source ??
@@ -31,7 +31,7 @@ export function defineEnv(shape, options) {
31
31
  const schema = shape[key];
32
32
  const result = schema["~standard"].validate(source[key]);
33
33
  if (result instanceof Promise) {
34
- // Env validation must be synchronous (it runs once, at import) — an async validator is a
34
+ // Env validation must be synchronous (it runs once, at import) - an async validator is a
35
35
  // configuration mistake, surfaced as a problem rather than an unhandled promise.
36
36
  problems.push(` ${key}: async validators are not supported in defineEnv`);
37
37
  continue;
@@ -45,7 +45,7 @@ export function defineEnv(shape, options) {
45
45
  }
46
46
  }
47
47
  if (problems.length > 0) {
48
- throw new Error(`[nifra/env] invalid environment — ${problems.length} problem(s):\n${problems.join("\n")}\n\nSet the variable(s) above and restart.`);
48
+ throw new Error(`[nifra/env] invalid environment - ${problems.length} problem(s):\n${problems.join("\n")}\n\nSet the variable(s) above and restart.`);
49
49
  }
50
50
  return Object.freeze(out);
51
51
  }
package/dist/helpers.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Coercing env validators. Every value in `process.env` is a `string | undefined`, so these turn
3
- * that into the typed value you actually want — with defaults, optionality, and clear errors. Each
3
+ * that into the typed value you actually want - with defaults, optionality, and clear errors. Each
4
4
  * is a Standard Schema, so they slot straight into {@link defineEnv} (and could be used anywhere a
5
5
  * Standard Schema is accepted).
6
6
  *
7
- * Error messages are **value-free** — they say what was wrong, never echo the variable's value
7
+ * Error messages are **value-free** - they say what was wrong, never echo the variable's value
8
8
  * (it may be a secret). {@link defineEnv} prepends the variable name.
9
9
  */
10
10
  import { type StandardSchemaV1 } from "./schema.js";
@@ -20,7 +20,7 @@ interface Optional {
20
20
  export declare function string(opts?: Base<string> & Optional): StandardSchemaV1<string | undefined>;
21
21
  /** A finite number, coerced from its decimal string. */
22
22
  export declare function number(opts?: Base<number> & Optional): StandardSchemaV1<number | undefined>;
23
- /** A TCP port: an integer in 1–65535. */
23
+ /** A TCP port: an integer in 1-65535. */
24
24
  export declare function port(opts?: Base<number>): StandardSchemaV1<number>;
25
25
  /** A boolean: `true`/`1`/`yes`/`on` → true; `false`/`0`/`no`/`off`/empty → false (case-insensitive). */
26
26
  export declare function boolean(opts?: Base<boolean>): StandardSchemaV1<boolean>;
@@ -28,7 +28,7 @@ export declare function boolean(opts?: Base<boolean>): StandardSchemaV1<boolean>
28
28
  export declare function enumValue<const V extends readonly [string, ...string[]]>(values: V, opts?: Base<V[number]>): StandardSchemaV1<V[number]>;
29
29
  /** A valid absolute URL (parses with the WHATWG `URL`). Returns the normalized href string. */
30
30
  export declare function url(opts?: Base<string> & Optional): StandardSchemaV1<string | undefined>;
31
- /** The coercing env validators, grouped — `env.string()`, `env.port()`, `env.enum([...])`, … */
31
+ /** The coercing env validators, grouped - `env.string()`, `env.port()`, `env.enum([...])`, … */
32
32
  export declare const env: {
33
33
  string: typeof string;
34
34
  number: typeof number;
package/dist/helpers.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Coercing env validators. Every value in `process.env` is a `string | undefined`, so these turn
3
- * that into the typed value you actually want — with defaults, optionality, and clear errors. Each
3
+ * that into the typed value you actually want - with defaults, optionality, and clear errors. Each
4
4
  * is a Standard Schema, so they slot straight into {@link defineEnv} (and could be used anywhere a
5
5
  * Standard Schema is accepted).
6
6
  *
7
- * Error messages are **value-free** — they say what was wrong, never echo the variable's value
7
+ * Error messages are **value-free** - they say what was wrong, never echo the variable's value
8
8
  * (it may be a secret). {@link defineEnv} prepends the variable name.
9
9
  */
10
10
  import { envSchema, issue } from "./schema.js";
@@ -38,7 +38,7 @@ export function number(opts = {}) {
38
38
  return { value: n };
39
39
  });
40
40
  }
41
- /** A TCP port: an integer in 1–65535. */
41
+ /** A TCP port: an integer in 1-65535. */
42
42
  export function port(opts = {}) {
43
43
  return envSchema((raw) => {
44
44
  if (isUnset(raw)) {
@@ -48,7 +48,7 @@ export function port(opts = {}) {
48
48
  }
49
49
  const n = Number(raw);
50
50
  if (!Number.isInteger(n) || n < 1 || n > 65535) {
51
- return issue("must be an integer port in 1–65535");
51
+ return issue("must be an integer port in 1-65535");
52
52
  }
53
53
  return { value: n };
54
54
  });
@@ -103,7 +103,7 @@ export function url(opts = {}) {
103
103
  }
104
104
  });
105
105
  }
106
- /** The coercing env validators, grouped — `env.string()`, `env.port()`, `env.enum([...])`, … */
106
+ /** The coercing env validators, grouped - `env.string()`, `env.port()`, `env.enum([...])`, … */
107
107
  export const env = {
108
108
  string,
109
109
  number,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/env — typed, validated environment variables. Define a schema once at startup; get a
2
+ * @nifrajs/env - typed, validated environment variables. Define a schema once at startup; get a
3
3
  * frozen typed object, or a loud boot-time failure listing every problem. Coercing helpers
4
4
  * (`env.number`/`port`/`boolean`/`url`/`enum`) turn `string | undefined` into the value you want;
5
5
  * any Standard Schema (`t`, zod, valibot) is also accepted. Dependency-free, edge-safe.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/env — typed, validated environment variables. Define a schema once at startup; get a
2
+ * @nifrajs/env - typed, validated environment variables. Define a schema once at startup; get a
3
3
  * frozen typed object, or a loud boot-time failure listing every problem. Coercing helpers
4
4
  * (`env.number`/`port`/`boolean`/`url`/`enum`) turn `string | undefined` into the value you want;
5
5
  * any Standard Schema (`t`, zod, valibot) is also accepted. Dependency-free, edge-safe.
package/dist/schema.d.ts CHANGED
@@ -26,7 +26,7 @@ export interface StandardSchemaV1<Output = unknown> {
26
26
  export type InferOutput<S extends StandardSchemaV1> = NonNullable<S["~standard"]["types"]>["output"];
27
27
  /** Build an env validator: a Standard Schema whose `validate` coerces from `string | undefined`. */
28
28
  export declare function envSchema<Output>(validate: (raw: string | undefined) => StandardResult<Output>): StandardSchemaV1<Output>;
29
- /** A single issue. Messages NEVER include the variable's value — it may be a secret. */
29
+ /** A single issue. Messages NEVER include the variable's value - it may be a secret. */
30
30
  export declare const issue: (message: string) => {
31
31
  readonly issues: ReadonlyArray<StandardIssue>;
32
32
  };
package/dist/schema.js CHANGED
@@ -15,7 +15,7 @@ export function envSchema(validate) {
15
15
  },
16
16
  };
17
17
  }
18
- /** A single issue. Messages NEVER include the variable's value — it may be a secret. */
18
+ /** A single issue. Messages NEVER include the variable's value - it may be a secret. */
19
19
  export const issue = (message) => ({
20
20
  issues: [{ message }],
21
21
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nifrajs/env",
3
- "version": "2.2.0",
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.",
3
+ "version": "2.4.0",
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",
7
7
  "typescript",
package/src/define.ts CHANGED
@@ -3,25 +3,25 @@ import type { InferOutput, StandardSchemaV1 } from "./schema.ts"
3
3
  /** A schema per variable name. */
4
4
  export type EnvShape = Record<string, StandardSchemaV1>
5
5
 
6
- /** The frozen, validated result — each key typed by its schema's output. */
6
+ /** The frozen, validated result - each key typed by its schema's output. */
7
7
  export type EnvResult<S extends EnvShape> = { readonly [K in keyof S]: InferOutput<S[K]> }
8
8
 
9
9
  export interface DefineEnvOptions {
10
10
  /**
11
11
  * Where to read variables from. Defaults to `process.env` (Bun/Node). On Cloudflare Workers there
12
- * is no `process.env` — pass the request's `env` bindings: `defineEnv(shape, { source: env })`.
12
+ * is no `process.env` - pass the request's `env` bindings: `defineEnv(shape, { source: env })`.
13
13
  */
14
14
  readonly source?: Record<string, string | undefined>
15
15
  }
16
16
 
17
17
  /**
18
- * Validate the environment against a schema and return a **frozen, typed** object — or throw at
18
+ * Validate the environment against a schema and return a **frozen, typed** object - or throw at
19
19
  * startup listing **every** problem at once (not just the first), so a misconfigured deploy fails
20
20
  * loud and immediately instead of erroring on the first request that touches a bad var. This is the
21
21
  * boot-time half of nifra's "validate at every boundary" rule, for config.
22
22
  *
23
23
  * ```ts
24
- * // env.ts — imported once at startup
24
+ * // env.ts - imported once at startup
25
25
  * import { defineEnv, env } from "@nifrajs/env"
26
26
  * export const ENV = defineEnv({
27
27
  * DATABASE_URL: env.url(),
@@ -33,9 +33,9 @@ export interface DefineEnvOptions {
33
33
  * // ENV.PORT: number, ENV.NODE_ENV: "development" | "production" | "test", … all validated.
34
34
  * ```
35
35
  *
36
- * Errors name the offending variable and the reason — never its value (it may be a secret). BYO
36
+ * Errors name the offending variable and the reason - never its value (it may be a secret). BYO
37
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.
38
+ * `t.number()` would see the raw string - use `env.number()` for coercion.
39
39
  */
40
40
  export function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptions): EnvResult<S> {
41
41
  const source =
@@ -49,7 +49,7 @@ export function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptio
49
49
  const schema = shape[key] as StandardSchemaV1
50
50
  const result = schema["~standard"].validate(source[key])
51
51
  if (result instanceof Promise) {
52
- // Env validation must be synchronous (it runs once, at import) — an async validator is a
52
+ // Env validation must be synchronous (it runs once, at import) - an async validator is a
53
53
  // configuration mistake, surfaced as a problem rather than an unhandled promise.
54
54
  problems.push(` ${key}: async validators are not supported in defineEnv`)
55
55
  continue
@@ -63,7 +63,7 @@ export function defineEnv<S extends EnvShape>(shape: S, options?: DefineEnvOptio
63
63
 
64
64
  if (problems.length > 0) {
65
65
  throw new Error(
66
- `[nifra/env] invalid environment — ${problems.length} problem(s):\n${problems.join("\n")}\n\nSet the variable(s) above and restart.`,
66
+ `[nifra/env] invalid environment - ${problems.length} problem(s):\n${problems.join("\n")}\n\nSet the variable(s) above and restart.`,
67
67
  )
68
68
  }
69
69
  return Object.freeze(out) as EnvResult<S>
package/src/helpers.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Coercing env validators. Every value in `process.env` is a `string | undefined`, so these turn
3
- * that into the typed value you actually want — with defaults, optionality, and clear errors. Each
3
+ * that into the typed value you actually want - with defaults, optionality, and clear errors. Each
4
4
  * is a Standard Schema, so they slot straight into {@link defineEnv} (and could be used anywhere a
5
5
  * Standard Schema is accepted).
6
6
  *
7
- * Error messages are **value-free** — they say what was wrong, never echo the variable's value
7
+ * Error messages are **value-free** - they say what was wrong, never echo the variable's value
8
8
  * (it may be a secret). {@link defineEnv} prepends the variable name.
9
9
  */
10
10
 
@@ -47,7 +47,7 @@ export function number(opts: Base<number> & Optional = {}): StandardSchemaV1<num
47
47
  })
48
48
  }
49
49
 
50
- /** A TCP port: an integer in 1–65535. */
50
+ /** A TCP port: an integer in 1-65535. */
51
51
  export function port(opts: Base<number> = {}): StandardSchemaV1<number> {
52
52
  return envSchema((raw) => {
53
53
  if (isUnset(raw)) {
@@ -56,7 +56,7 @@ export function port(opts: Base<number> = {}): StandardSchemaV1<number> {
56
56
  }
57
57
  const n = Number(raw)
58
58
  if (!Number.isInteger(n) || n < 1 || n > 65535) {
59
- return issue("must be an integer port in 1–65535")
59
+ return issue("must be an integer port in 1-65535")
60
60
  }
61
61
  return { value: n }
62
62
  }) as StandardSchemaV1<number>
@@ -111,7 +111,7 @@ export function url(opts: Base<string> & Optional = {}): StandardSchemaV1<string
111
111
  })
112
112
  }
113
113
 
114
- /** The coercing env validators, grouped — `env.string()`, `env.port()`, `env.enum([...])`, … */
114
+ /** The coercing env validators, grouped - `env.string()`, `env.port()`, `env.enum([...])`, … */
115
115
  export const env = {
116
116
  string,
117
117
  number,
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nifrajs/env — typed, validated environment variables. Define a schema once at startup; get a
2
+ * @nifrajs/env - typed, validated environment variables. Define a schema once at startup; get a
3
3
  * frozen typed object, or a loud boot-time failure listing every problem. Coercing helpers
4
4
  * (`env.number`/`port`/`boolean`/`url`/`enum`) turn `string | undefined` into the value you want;
5
5
  * any Standard Schema (`t`, zod, valibot) is also accepted. Dependency-free, edge-safe.
package/src/schema.ts CHANGED
@@ -39,7 +39,7 @@ export function envSchema<Output>(
39
39
  }
40
40
  }
41
41
 
42
- /** A single issue. Messages NEVER include the variable's value — it may be a secret. */
42
+ /** A single issue. Messages NEVER include the variable's value - it may be a secret. */
43
43
  export const issue = (message: string): { readonly issues: ReadonlyArray<StandardIssue> } => ({
44
44
  issues: [{ message }],
45
45
  })