typed-settings 0.1.0 → 0.1.4
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 +4 -2
- package/dist/adapters/joi.d.cts +13 -0
- package/dist/adapters/joi.d.ts +13 -0
- package/dist/adapters/zod.d.cts +16 -0
- package/dist/adapters/zod.d.ts +16 -0
- package/dist/{chunk-VTIYOSG2.js → chunk-DEP5SD4J.js} +1 -1
- package/dist/{chunk-RCO6K3WQ.js → chunk-YVJEZPPZ.js} +11 -6
- package/dist/cli/main.cjs +11 -6
- package/dist/cli/main.d.cts +4 -0
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +2 -2
- package/dist/{errors-IU9n4f3t.d.cts → errors-itGaU4Q8.d.cts} +5 -0
- package/dist/{errors-IU9n4f3t.d.ts → errors-itGaU4Q8.d.ts} +5 -0
- package/dist/formats/env.d.cts +5 -0
- package/dist/formats/env.d.ts +5 -0
- package/dist/formats/json.d.cts +4 -0
- package/dist/formats/json.d.ts +4 -0
- package/dist/formats/toml.d.cts +4 -0
- package/dist/formats/toml.d.ts +4 -0
- package/dist/formats/yaml.d.cts +5 -0
- package/dist/formats/yaml.d.ts +5 -0
- package/dist/framework/next.cjs +11 -6
- package/dist/framework/next.d.cts +16 -3
- package/dist/framework/next.d.ts +16 -3
- package/dist/framework/next.js +1 -1
- package/dist/framework/vite.cjs +11 -6
- package/dist/framework/vite.d.cts +16 -3
- package/dist/framework/vite.d.ts +16 -3
- package/dist/framework/vite.js +2 -2
- package/dist/index.cjs +11 -6
- package/dist/index.d.cts +42 -3
- package/dist/index.d.ts +42 -3
- package/dist/index.js +1 -1
- package/dist/node.cjs +11 -6
- package/dist/node.d.cts +29 -2
- package/dist/node.d.ts +29 -2
- package/dist/node.js +2 -2
- package/dist/{shared-DBcV6jIy.d.cts → shared-CucO_XsG.d.cts} +1 -0
- package/dist/{shared-DBcV6jIy.d.ts → shared-CucO_XsG.d.ts} +1 -0
- package/dist/types-B_Dc2L4T.d.cts +69 -0
- package/dist/types-B_Dc2L4T.d.ts +69 -0
- package/dist/vault/aws.d.cts +26 -1
- package/dist/vault/aws.d.ts +26 -1
- package/dist/vault/hashicorp.d.cts +23 -2
- package/dist/vault/hashicorp.d.ts +23 -2
- package/dist/vault/http.d.cts +20 -2
- package/dist/vault/http.d.ts +20 -2
- package/package.json +9 -1
- package/dist/types-BswIPp7U.d.cts +0 -41
- package/dist/types-BswIPp7U.d.ts +0 -41
package/README.md
CHANGED
|
@@ -185,7 +185,7 @@ Provider details: [docs/vault.md](docs/vault.md).
|
|
|
185
185
|
| `schema` | Standard Schema | required | zod / valibot / arktype object, or a legacy bridge. An async `validate()` forces `settingsAsync()` |
|
|
186
186
|
| `sources` | array | `['.env', 'env']` | layers in priority order, later wins |
|
|
187
187
|
| `prefix` | `string` | - | global prefix strip, case-insensitive, once |
|
|
188
|
-
| `envMap` | object |
|
|
188
|
+
| `envMap` | object | `{}` | maps an env key to the literal key it should occupy (used as-is: no strip/split) |
|
|
189
189
|
| `env` | object | `process.env` | the env snapshot. Pass `{}` to isolate, or a map in tests/on Edge |
|
|
190
190
|
| `expand` | `boolean` | `true` | `$VAR` expansion after merging. `false` leaves literals alone |
|
|
191
191
|
| `allowUnresolved` | `boolean` | `false` | `true` keeps `${MISSING}` as-is instead of throwing |
|
|
@@ -279,7 +279,9 @@ Things people actually hit, in rough order of frequency:
|
|
|
279
279
|
|
|
280
280
|
- **`USE_ASYNC: provider is async`.** One of your providers (or the schema itself) is async. Switch to `settingsAsync()`.
|
|
281
281
|
- **`E_UNRESOLVED: FOO missing`.** A `$FOO` reference points at nothing. Set the variable, give it a default (`${FOO:-fallback}`), or pass `allowUnresolved: true` to leave it literal.
|
|
282
|
-
- **Schema rejects everything.** Keys are lowercased during load, so schemas need lowercase keys
|
|
282
|
+
- **Schema rejects everything.** Keys are lowercased during load, so schemas need lowercase keys (`port`, not `PORT`). The failure mode is sneaky: `z.object({ PORT: z.coerce.number() })` never matches the lowercased input, so it validates `undefined`, and `z.coerce.number()` turns that into `NaN` — you get the confusing "expected number, received NaN".
|
|
283
|
+
- **Everything is silently empty or wrong.** Most often a global `prefix` ate your keys: matching applies to every source, so `prefix: 'APP_'` drops a YAML key like `port:` and a secrets-dir entry like `API_TOKEN` without a word. Scope it per source, or skip it and bridge env names via `envMap`.
|
|
284
|
+
- **Deno (JSR) refuses a fresh release.** Deno's minimum-dependency-age policy blocks versions published within ~24h. For local dev, run with `--minimum-dependency-age=0`.
|
|
283
285
|
- **`E_NO_FS` under ESM.** Core can't reach `node:fs` on its own. Import `typed-settings/node` once, or stick to `{ text }` / `{ map }` sources.
|
|
284
286
|
- **`E_UNKNOWN_KEY`.** Extra keys with `unknownKeys: 'reject'` (the CLI calls this `--strict`). Either drop the keys or switch to `strip` / `preserve`.
|
|
285
287
|
- **`SCHEMA_LOAD_ERROR`.** The CLI can't find your schema. Export it under the name `schema`, or point at it with `--schema-export NAME`.
|
package/dist/adapters/joi.d.cts
CHANGED
|
@@ -4,7 +4,16 @@ type AnySchema = {
|
|
|
4
4
|
validateSync?: (v: unknown, o?: unknown) => unknown;
|
|
5
5
|
validate?: (...a: never[]) => unknown;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Adapts a Yup schema via `validateSync` (`stripUnknown`, all errors).
|
|
9
|
+
* `inner[]` failures map to issues; anything else becomes a root issue.
|
|
10
|
+
*/
|
|
7
11
|
declare function yupAdapter(schema: any): StandardSchemaV1;
|
|
12
|
+
/**
|
|
13
|
+
* Adapts a Joi schema (`validate` with convert + stripUnknown). `details[]`
|
|
14
|
+
* map to issues; a throwing `validate()` or empty details still yields a
|
|
15
|
+
* non-empty issues array, as Standard Schema requires.
|
|
16
|
+
*/
|
|
8
17
|
declare function joiAdapter(schema: AnySchema & {
|
|
9
18
|
validate?: (v: unknown, o?: unknown) => {
|
|
10
19
|
error?: {
|
|
@@ -17,6 +26,10 @@ declare function joiAdapter(schema: AnySchema & {
|
|
|
17
26
|
value: unknown;
|
|
18
27
|
};
|
|
19
28
|
}): StandardSchemaV1;
|
|
29
|
+
/**
|
|
30
|
+
* Adapts a Superstruct struct via `create()`. `failures()` map to issues;
|
|
31
|
+
* anything else falls back to the thrown message.
|
|
32
|
+
*/
|
|
20
33
|
declare function superstructAdapter(schema: AnySchema & {
|
|
21
34
|
create?: (v: unknown) => unknown;
|
|
22
35
|
}): StandardSchemaV1;
|
package/dist/adapters/joi.d.ts
CHANGED
|
@@ -4,7 +4,16 @@ type AnySchema = {
|
|
|
4
4
|
validateSync?: (v: unknown, o?: unknown) => unknown;
|
|
5
5
|
validate?: (...a: never[]) => unknown;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Adapts a Yup schema via `validateSync` (`stripUnknown`, all errors).
|
|
9
|
+
* `inner[]` failures map to issues; anything else becomes a root issue.
|
|
10
|
+
*/
|
|
7
11
|
declare function yupAdapter(schema: any): StandardSchemaV1;
|
|
12
|
+
/**
|
|
13
|
+
* Adapts a Joi schema (`validate` with convert + stripUnknown). `details[]`
|
|
14
|
+
* map to issues; a throwing `validate()` or empty details still yields a
|
|
15
|
+
* non-empty issues array, as Standard Schema requires.
|
|
16
|
+
*/
|
|
8
17
|
declare function joiAdapter(schema: AnySchema & {
|
|
9
18
|
validate?: (v: unknown, o?: unknown) => {
|
|
10
19
|
error?: {
|
|
@@ -17,6 +26,10 @@ declare function joiAdapter(schema: AnySchema & {
|
|
|
17
26
|
value: unknown;
|
|
18
27
|
};
|
|
19
28
|
}): StandardSchemaV1;
|
|
29
|
+
/**
|
|
30
|
+
* Adapts a Superstruct struct via `create()`. `failures()` map to issues;
|
|
31
|
+
* anything else falls back to the thrown message.
|
|
32
|
+
*/
|
|
20
33
|
declare function superstructAdapter(schema: AnySchema & {
|
|
21
34
|
create?: (v: unknown) => unknown;
|
|
22
35
|
}): StandardSchemaV1;
|
package/dist/adapters/zod.d.cts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Zod helpers: `withPrefix` scopes any Standard Schema under an env prefix,
|
|
5
|
+
* `coerceEnv` is the identity hook for composed pipelines.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Scopes a schema under `prefix`: matching keys strip case-insensitively before
|
|
12
|
+
* validation, prefixed keys win collisions, non-objects pass through untouched.
|
|
13
|
+
* An empty prefix returns the schema unchanged.
|
|
14
|
+
*/
|
|
3
15
|
declare function withPrefix<S extends StandardSchemaV1>(schema: S, prefix: string): S;
|
|
16
|
+
/**
|
|
17
|
+
* Identity hook for composed pipelines. Documents "this value already went
|
|
18
|
+
* through env coercion"; the real logic lives in `coerce.ts`.
|
|
19
|
+
*/
|
|
4
20
|
declare function coerceEnv(value: unknown): unknown;
|
|
5
21
|
|
|
6
22
|
export { coerceEnv, withPrefix };
|
package/dist/adapters/zod.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Zod helpers: `withPrefix` scopes any Standard Schema under an env prefix,
|
|
5
|
+
* `coerceEnv` is the identity hook for composed pipelines.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Scopes a schema under `prefix`: matching keys strip case-insensitively before
|
|
12
|
+
* validation, prefixed keys win collisions, non-objects pass through untouched.
|
|
13
|
+
* An empty prefix returns the schema unchanged.
|
|
14
|
+
*/
|
|
3
15
|
declare function withPrefix<S extends StandardSchemaV1>(schema: S, prefix: string): S;
|
|
16
|
+
/**
|
|
17
|
+
* Identity hook for composed pipelines. Documents "this value already went
|
|
18
|
+
* through env coercion"; the real logic lives in `coerce.ts`.
|
|
19
|
+
*/
|
|
4
20
|
declare function coerceEnv(value: unknown): unknown;
|
|
5
21
|
|
|
6
22
|
export { coerceEnv, withPrefix };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { settings } from './chunk-
|
|
1
|
+
import { settings } from './chunk-YVJEZPPZ.js';
|
|
2
2
|
import { parseEnvText } from './chunk-F6DX3HXZ.js';
|
|
3
3
|
import { readFileSync, readdirSync, statSync, watch } from 'fs';
|
|
4
4
|
import { join, dirname, basename, resolve } from 'path';
|
|
@@ -253,12 +253,12 @@ function expandKeys(flat, opts) {
|
|
|
253
253
|
const stripped = stripPrefix(rawKey);
|
|
254
254
|
if (stripped === null) continue;
|
|
255
255
|
const useKey = stripped;
|
|
256
|
-
if (useKey.
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
257
|
+
const parts = useKey.split("__");
|
|
258
|
+
const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
|
|
259
|
+
if (cleanSplit) {
|
|
259
260
|
for (const p of parts) {
|
|
260
261
|
if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
261
|
-
if (!p) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_EMPTY_SEGMENT" }], "E_EMPTY_SEGMENT");
|
|
262
262
|
}
|
|
263
263
|
const lowered = parts.map((p) => p.toLowerCase());
|
|
264
264
|
const top = lowered[0];
|
|
@@ -290,7 +290,6 @@ function expandKeys(flat, opts) {
|
|
|
290
290
|
setPath(out, lowered, value);
|
|
291
291
|
} else {
|
|
292
292
|
const k = useKey.toLowerCase();
|
|
293
|
-
if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
|
|
294
293
|
const kind = kindOf(k);
|
|
295
294
|
if (kind.indexed) {
|
|
296
295
|
throw new ConfigError(
|
|
@@ -791,7 +790,13 @@ function makeLookup(merged, envSnapshot) {
|
|
|
791
790
|
function expandDeepStrings(obj, lookup, ctx, path = []) {
|
|
792
791
|
if (typeof obj === "string") {
|
|
793
792
|
const top = (path[0] ?? "<root>").toLowerCase();
|
|
794
|
-
|
|
793
|
+
const from = ctx.fromMap.get(top) ?? "config";
|
|
794
|
+
try {
|
|
795
|
+
return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
|
|
796
|
+
} catch (e) {
|
|
797
|
+
if (from === "env") return obj;
|
|
798
|
+
throw e;
|
|
799
|
+
}
|
|
795
800
|
}
|
|
796
801
|
if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
|
|
797
802
|
if (obj && typeof obj === "object") {
|
package/dist/cli/main.cjs
CHANGED
|
@@ -485,12 +485,12 @@ function expandKeys(flat, opts) {
|
|
|
485
485
|
const stripped = stripPrefix(rawKey);
|
|
486
486
|
if (stripped === null) continue;
|
|
487
487
|
const useKey = stripped;
|
|
488
|
-
if (useKey.
|
|
489
|
-
|
|
490
|
-
|
|
488
|
+
if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
489
|
+
const parts = useKey.split("__");
|
|
490
|
+
const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
|
|
491
|
+
if (cleanSplit) {
|
|
491
492
|
for (const p of parts) {
|
|
492
493
|
if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
493
|
-
if (!p) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_EMPTY_SEGMENT" }], "E_EMPTY_SEGMENT");
|
|
494
494
|
}
|
|
495
495
|
const lowered = parts.map((p) => p.toLowerCase());
|
|
496
496
|
const top = lowered[0];
|
|
@@ -522,7 +522,6 @@ function expandKeys(flat, opts) {
|
|
|
522
522
|
setPath(out, lowered, value);
|
|
523
523
|
} else {
|
|
524
524
|
const k = useKey.toLowerCase();
|
|
525
|
-
if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
|
|
526
525
|
const kind = kindOf(k);
|
|
527
526
|
if (kind.indexed) {
|
|
528
527
|
throw new ConfigError(
|
|
@@ -1044,7 +1043,13 @@ function makeLookup(merged, envSnapshot) {
|
|
|
1044
1043
|
function expandDeepStrings(obj, lookup, ctx, path = []) {
|
|
1045
1044
|
if (typeof obj === "string") {
|
|
1046
1045
|
const top = (path[0] ?? "<root>").toLowerCase();
|
|
1047
|
-
|
|
1046
|
+
const from = ctx.fromMap.get(top) ?? "config";
|
|
1047
|
+
try {
|
|
1048
|
+
return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
|
|
1049
|
+
} catch (e) {
|
|
1050
|
+
if (from === "env") return obj;
|
|
1051
|
+
throw e;
|
|
1052
|
+
}
|
|
1048
1053
|
}
|
|
1049
1054
|
if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
|
|
1050
1055
|
if (obj && typeof obj === "object") {
|
package/dist/cli/main.d.cts
CHANGED
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { watchSettings } from '../chunk-
|
|
3
|
-
import { settings } from '../chunk-
|
|
2
|
+
import { watchSettings } from '../chunk-DEP5SD4J.js';
|
|
3
|
+
import { settings } from '../chunk-YVJEZPPZ.js';
|
|
4
4
|
import '../chunk-33M5GIKQ.js';
|
|
5
5
|
import '../chunk-OVFMKC2O.js';
|
|
6
6
|
import '../chunk-UFUHHR2J.js';
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
/** One validation failure: the key path, the winning source, and what went wrong. */
|
|
1
2
|
interface ConfigIssue {
|
|
2
3
|
path: string;
|
|
3
4
|
from: string;
|
|
4
5
|
message: string;
|
|
5
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Every settings failure. Carries machine-readable `issues` plus a `code`
|
|
9
|
+
* (`E_INVALID_CONFIG` by default, e.g. `E_UNKNOWN_KEY`, `E_TIMEOUT`).
|
|
10
|
+
*/
|
|
6
11
|
declare class ConfigError extends Error {
|
|
7
12
|
code: string;
|
|
8
13
|
issues: ConfigIssue[];
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
/** One validation failure: the key path, the winning source, and what went wrong. */
|
|
1
2
|
interface ConfigIssue {
|
|
2
3
|
path: string;
|
|
3
4
|
from: string;
|
|
4
5
|
message: string;
|
|
5
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Every settings failure. Carries machine-readable `issues` plus a `code`
|
|
9
|
+
* (`E_INVALID_CONFIG` by default, e.g. `E_UNKNOWN_KEY`, `E_TIMEOUT`).
|
|
10
|
+
*/
|
|
6
11
|
declare class ConfigError extends Error {
|
|
7
12
|
code: string;
|
|
8
13
|
issues: ConfigIssue[];
|
package/dist/formats/env.d.cts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses dotenv text into a flat map. Strips one BOM, joins multiline
|
|
3
|
+
* double-quoted values, lets the last duplicate win. Throws `ParseError` on
|
|
4
|
+
* backticks, unterminated quotes, bare keys, and empty keys.
|
|
5
|
+
*/
|
|
1
6
|
declare function parseEnvText(text: string): Record<string, string>;
|
|
2
7
|
|
|
3
8
|
export { parseEnvText };
|
package/dist/formats/env.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses dotenv text into a flat map. Strips one BOM, joins multiline
|
|
3
|
+
* double-quoted values, lets the last duplicate win. Throws `ParseError` on
|
|
4
|
+
* backticks, unterminated quotes, bare keys, and empty keys.
|
|
5
|
+
*/
|
|
1
6
|
declare function parseEnvText(text: string): Record<string, string>;
|
|
2
7
|
|
|
3
8
|
export { parseEnvText };
|
package/dist/formats/json.d.cts
CHANGED
package/dist/formats/json.d.ts
CHANGED
package/dist/formats/toml.d.cts
CHANGED
package/dist/formats/toml.d.ts
CHANGED
package/dist/formats/yaml.d.cts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-doc YAML parse (1.2, duplicate keys rejected). A trailing lone `---`
|
|
3
|
+
* still parses; multi-doc payloads, bad indentation, and unresolvable aliases
|
|
4
|
+
* throw `ParseError` naming the source. Explicit `null` reads as `{}`.
|
|
5
|
+
*/
|
|
1
6
|
declare function parseYamlText(text: string, from?: string): unknown;
|
|
2
7
|
|
|
3
8
|
export { parseYamlText };
|
package/dist/formats/yaml.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-doc YAML parse (1.2, duplicate keys rejected). A trailing lone `---`
|
|
3
|
+
* still parses; multi-doc payloads, bad indentation, and unresolvable aliases
|
|
4
|
+
* throw `ParseError` naming the source. Explicit `null` reads as `{}`.
|
|
5
|
+
*/
|
|
1
6
|
declare function parseYamlText(text: string, from?: string): unknown;
|
|
2
7
|
|
|
3
8
|
export { parseYamlText };
|
package/dist/framework/next.cjs
CHANGED
|
@@ -440,12 +440,12 @@ function expandKeys(flat, opts) {
|
|
|
440
440
|
const stripped = stripPrefix(rawKey);
|
|
441
441
|
if (stripped === null) continue;
|
|
442
442
|
const useKey = stripped;
|
|
443
|
-
if (useKey.
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
444
|
+
const parts = useKey.split("__");
|
|
445
|
+
const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
|
|
446
|
+
if (cleanSplit) {
|
|
446
447
|
for (const p of parts) {
|
|
447
448
|
if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
448
|
-
if (!p) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_EMPTY_SEGMENT" }], "E_EMPTY_SEGMENT");
|
|
449
449
|
}
|
|
450
450
|
const lowered = parts.map((p) => p.toLowerCase());
|
|
451
451
|
const top = lowered[0];
|
|
@@ -477,7 +477,6 @@ function expandKeys(flat, opts) {
|
|
|
477
477
|
setPath(out, lowered, value);
|
|
478
478
|
} else {
|
|
479
479
|
const k = useKey.toLowerCase();
|
|
480
|
-
if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
|
|
481
480
|
const kind = kindOf(k);
|
|
482
481
|
if (kind.indexed) {
|
|
483
482
|
throw new ConfigError(
|
|
@@ -949,7 +948,13 @@ function makeLookup(merged, envSnapshot) {
|
|
|
949
948
|
function expandDeepStrings(obj, lookup, ctx, path = []) {
|
|
950
949
|
if (typeof obj === "string") {
|
|
951
950
|
const top = (path[0] ?? "<root>").toLowerCase();
|
|
952
|
-
|
|
951
|
+
const from = ctx.fromMap.get(top) ?? "config";
|
|
952
|
+
try {
|
|
953
|
+
return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
|
|
954
|
+
} catch (e) {
|
|
955
|
+
if (from === "env") return obj;
|
|
956
|
+
throw e;
|
|
957
|
+
}
|
|
953
958
|
}
|
|
954
959
|
if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
|
|
955
960
|
if (obj && typeof obj === "object") {
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
export { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
export { pickPublic, settings, settingsAsync } from '../index.cjs';
|
|
3
|
-
export { S as SettingsOptions } from '../types-
|
|
4
|
-
export { C as ConfigError } from '../errors-
|
|
3
|
+
export { S as SettingsOptions } from '../types-B_Dc2L4T.cjs';
|
|
4
|
+
export { C as ConfigError } from '../errors-itGaU4Q8.cjs';
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Next.js App Router binding (Edge-safe: no `fs`, no static `server-only` import).
|
|
8
|
+
* Load the full config on the server, hand the client only an explicit subset.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: add `import 'server-only'` at the top of YOUR server settings file
|
|
11
|
+
* (not inside this library — the `server-only` package throws when evaluated
|
|
12
|
+
* outside a React Server Component, which would break plain Node/vitest usage).
|
|
13
|
+
* // settings.ts (server)
|
|
14
|
+
* import 'server-only';
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Explicit public subset - no spread, keys enumerated so secrets can't leak via `...cfg`. */
|
|
7
20
|
declare function publicSettings<T extends object, K extends keyof T>(cfg: T, keys: readonly K[]): Pick<T, K>;
|
|
8
21
|
|
|
9
22
|
export { publicSettings };
|
package/dist/framework/next.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
export { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
export { pickPublic, settings, settingsAsync } from '../index.js';
|
|
3
|
-
export { S as SettingsOptions } from '../types-
|
|
4
|
-
export { C as ConfigError } from '../errors-
|
|
3
|
+
export { S as SettingsOptions } from '../types-B_Dc2L4T.js';
|
|
4
|
+
export { C as ConfigError } from '../errors-itGaU4Q8.js';
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Next.js App Router binding (Edge-safe: no `fs`, no static `server-only` import).
|
|
8
|
+
* Load the full config on the server, hand the client only an explicit subset.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: add `import 'server-only'` at the top of YOUR server settings file
|
|
11
|
+
* (not inside this library — the `server-only` package throws when evaluated
|
|
12
|
+
* outside a React Server Component, which would break plain Node/vitest usage).
|
|
13
|
+
* // settings.ts (server)
|
|
14
|
+
* import 'server-only';
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Explicit public subset - no spread, keys enumerated so secrets can't leak via `...cfg`. */
|
|
7
20
|
declare function publicSettings<T extends object, K extends keyof T>(cfg: T, keys: readonly K[]): Pick<T, K>;
|
|
8
21
|
|
|
9
22
|
export { publicSettings };
|
package/dist/framework/next.js
CHANGED
package/dist/framework/vite.cjs
CHANGED
|
@@ -440,12 +440,12 @@ function expandKeys(flat, opts) {
|
|
|
440
440
|
const stripped = stripPrefix(rawKey);
|
|
441
441
|
if (stripped === null) continue;
|
|
442
442
|
const useKey = stripped;
|
|
443
|
-
if (useKey.
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
444
|
+
const parts = useKey.split("__");
|
|
445
|
+
const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
|
|
446
|
+
if (cleanSplit) {
|
|
446
447
|
for (const p of parts) {
|
|
447
448
|
if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
448
|
-
if (!p) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_EMPTY_SEGMENT" }], "E_EMPTY_SEGMENT");
|
|
449
449
|
}
|
|
450
450
|
const lowered = parts.map((p) => p.toLowerCase());
|
|
451
451
|
const top = lowered[0];
|
|
@@ -477,7 +477,6 @@ function expandKeys(flat, opts) {
|
|
|
477
477
|
setPath(out, lowered, value);
|
|
478
478
|
} else {
|
|
479
479
|
const k = useKey.toLowerCase();
|
|
480
|
-
if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
|
|
481
480
|
const kind = kindOf(k);
|
|
482
481
|
if (kind.indexed) {
|
|
483
482
|
throw new ConfigError(
|
|
@@ -949,7 +948,13 @@ function makeLookup(merged, envSnapshot) {
|
|
|
949
948
|
function expandDeepStrings(obj, lookup, ctx, path = []) {
|
|
950
949
|
if (typeof obj === "string") {
|
|
951
950
|
const top = (path[0] ?? "<root>").toLowerCase();
|
|
952
|
-
|
|
951
|
+
const from = ctx.fromMap.get(top) ?? "config";
|
|
952
|
+
try {
|
|
953
|
+
return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
|
|
954
|
+
} catch (e) {
|
|
955
|
+
if (from === "env") return obj;
|
|
956
|
+
throw e;
|
|
957
|
+
}
|
|
953
958
|
}
|
|
954
959
|
if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
|
|
955
960
|
if (obj && typeof obj === "object") {
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
export { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
3
|
export { pickPublic, settings, settingsAsync } from '../index.cjs';
|
|
4
|
-
import { S as SettingsOptions, F as Flat } from '../types-
|
|
5
|
-
export { C as ConfigError } from '../errors-
|
|
4
|
+
import { S as SettingsOptions, F as Flat } from '../types-B_Dc2L4T.cjs';
|
|
5
|
+
export { C as ConfigError } from '../errors-itGaU4Q8.cjs';
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Vite binding (Edge-safe, no `fs`). Validates `import.meta.env` against a schema.
|
|
9
|
+
*
|
|
10
|
+
* Rules: never spread `import.meta.env` (it drags server secrets into the
|
|
11
|
+
* client bundle). Pass it as a map; file preloading belongs in `vite.config.ts`
|
|
12
|
+
* via `loadEnvFiles()` passed as `{ text }`.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validates `import.meta.env` (passed explicitly by the caller) against a schema.
|
|
19
|
+
* Sources and ambient env are fixed: the map is the only input.
|
|
20
|
+
*/
|
|
8
21
|
declare function viteSettings<S extends StandardSchemaV1>(opts: Omit<SettingsOptions<S>, 'sources' | 'env'>, metaEnv: Flat): StandardSchemaV1.InferOutput<S>;
|
|
9
22
|
|
|
10
23
|
export { Flat, SettingsOptions, viteSettings };
|
package/dist/framework/vite.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
export { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
3
|
export { pickPublic, settings, settingsAsync } from '../index.js';
|
|
4
|
-
import { S as SettingsOptions, F as Flat } from '../types-
|
|
5
|
-
export { C as ConfigError } from '../errors-
|
|
4
|
+
import { S as SettingsOptions, F as Flat } from '../types-B_Dc2L4T.js';
|
|
5
|
+
export { C as ConfigError } from '../errors-itGaU4Q8.js';
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Vite binding (Edge-safe, no `fs`). Validates `import.meta.env` against a schema.
|
|
9
|
+
*
|
|
10
|
+
* Rules: never spread `import.meta.env` (it drags server secrets into the
|
|
11
|
+
* client bundle). Pass it as a map; file preloading belongs in `vite.config.ts`
|
|
12
|
+
* via `loadEnvFiles()` passed as `{ text }`.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validates `import.meta.env` (passed explicitly by the caller) against a schema.
|
|
19
|
+
* Sources and ambient env are fixed: the map is the only input.
|
|
20
|
+
*/
|
|
8
21
|
declare function viteSettings<S extends StandardSchemaV1>(opts: Omit<SettingsOptions<S>, 'sources' | 'env'>, metaEnv: Flat): StandardSchemaV1.InferOutput<S>;
|
|
9
22
|
|
|
10
23
|
export { Flat, SettingsOptions, viteSettings };
|
package/dist/framework/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { settings } from '../chunk-
|
|
2
|
-
export { pickPublic, settings, settingsAsync } from '../chunk-
|
|
1
|
+
import { settings } from '../chunk-YVJEZPPZ.js';
|
|
2
|
+
export { pickPublic, settings, settingsAsync } from '../chunk-YVJEZPPZ.js';
|
|
3
3
|
import '../chunk-33M5GIKQ.js';
|
|
4
4
|
import '../chunk-OVFMKC2O.js';
|
|
5
5
|
import '../chunk-UFUHHR2J.js';
|
package/dist/index.cjs
CHANGED
|
@@ -440,12 +440,12 @@ function expandKeys(flat, opts) {
|
|
|
440
440
|
const stripped = stripPrefix(rawKey);
|
|
441
441
|
if (stripped === null) continue;
|
|
442
442
|
const useKey = stripped;
|
|
443
|
-
if (useKey.
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
if (FORBIDDEN.has(useKey.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
444
|
+
const parts = useKey.split("__");
|
|
445
|
+
const cleanSplit = parts.length > 1 && parts.every((p) => p !== "");
|
|
446
|
+
if (cleanSplit) {
|
|
446
447
|
for (const p of parts) {
|
|
447
448
|
if (FORBIDDEN.has(p.toLowerCase())) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO: forbidden key" }], "E_PROTO");
|
|
448
|
-
if (!p) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_EMPTY_SEGMENT" }], "E_EMPTY_SEGMENT");
|
|
449
449
|
}
|
|
450
450
|
const lowered = parts.map((p) => p.toLowerCase());
|
|
451
451
|
const top = lowered[0];
|
|
@@ -477,7 +477,6 @@ function expandKeys(flat, opts) {
|
|
|
477
477
|
setPath(out, lowered, value);
|
|
478
478
|
} else {
|
|
479
479
|
const k = useKey.toLowerCase();
|
|
480
|
-
if (FORBIDDEN.has(k)) throw new ConfigError([{ path: rawKey, from: "keys", message: "E_PROTO" }], "E_PROTO");
|
|
481
480
|
const kind = kindOf(k);
|
|
482
481
|
if (kind.indexed) {
|
|
483
482
|
throw new ConfigError(
|
|
@@ -978,7 +977,13 @@ function makeLookup(merged, envSnapshot) {
|
|
|
978
977
|
function expandDeepStrings(obj, lookup, ctx, path = []) {
|
|
979
978
|
if (typeof obj === "string") {
|
|
980
979
|
const top = (path[0] ?? "<root>").toLowerCase();
|
|
981
|
-
|
|
980
|
+
const from = ctx.fromMap.get(top) ?? "config";
|
|
981
|
+
try {
|
|
982
|
+
return expandLeaf(obj, lookup, { ...ctx, from }, path.map((p) => p.toLowerCase()));
|
|
983
|
+
} catch (e) {
|
|
984
|
+
if (from === "env") return obj;
|
|
985
|
+
throw e;
|
|
986
|
+
}
|
|
982
987
|
}
|
|
983
988
|
if (Array.isArray(obj)) return obj.map((x, i) => expandDeepStrings(x, lookup, ctx, [...path, String(i)]));
|
|
984
989
|
if (obj && typeof obj === "object") {
|