@clipboard-health/config 0.1.0 → 0.2.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 +70 -1
- package/package.json +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/index.js.map +1 -1
- package/src/lib/{config.js → createConfig.js} +4 -2
- package/src/lib/createConfig.js.map +1 -0
- package/src/lib/config.js.map +0 -1
- /package/src/lib/{config.d.ts → createConfig.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -19,7 +19,76 @@ npm install @clipboard-health/config
|
|
|
19
19
|
|
|
20
20
|
### Type-safe configuration
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The TypeDoc comment for the `createConfig` function:
|
|
23
|
+
|
|
24
|
+
<!-- prettier-ignore -->
|
|
25
|
+
```ts
|
|
26
|
+
// ./src/lib/createConfig.ts
|
|
27
|
+
|
|
28
|
+
import { fromZodError } from "zod-validation-error";
|
|
29
|
+
|
|
30
|
+
import { deepFreeze } from "./internal/deepFreeze";
|
|
31
|
+
import { resolve } from "./internal/resolver";
|
|
32
|
+
import { type ConfigParams } from "./types";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Type-safe static configuration management: a pure function to resolve, validate against a Zod
|
|
36
|
+
* schema, and freeze configuration values.
|
|
37
|
+
*
|
|
38
|
+
* Configuration values resolve in order from highest precedence to lowest:
|
|
39
|
+
* 1. Environment variables
|
|
40
|
+
* - Resolved converting configuration path from camelCase to UPPER_SNAKE. For example, the `{
|
|
41
|
+
* myApi: { port: 3000 } }` configuration resolves to `MY_API_PORT`.
|
|
42
|
+
* 2. Environment-specific overrides, {@link ConfigValue.overrides}
|
|
43
|
+
* 3. Default values, {@link ConfigValue.defaultValue}
|
|
44
|
+
*
|
|
45
|
+
* Supported configuration value types:
|
|
46
|
+
* - bigint
|
|
47
|
+
* - boolean
|
|
48
|
+
* - date
|
|
49
|
+
* - number
|
|
50
|
+
* - string
|
|
51
|
+
* - arrays and nested objects using the above types
|
|
52
|
+
*
|
|
53
|
+
* To override arrays with environment variables, use stringified JSON arrays, e.g. `["a","b"]`.
|
|
54
|
+
*
|
|
55
|
+
* **IMPORTANT**: To avoid runtime errors:
|
|
56
|
+
* 1. Environment variables are strings, so use `z.coerce` Zod types for those you plan to override.
|
|
57
|
+
* Note that `z.coerce.boolean()` coerces any truthy value to `true`. To restrict to `"true" |
|
|
58
|
+
* "false"`, use the
|
|
59
|
+
* {@link https://github.com/ClipboardHealth/core-utils/blob/main/packages/contract-core/src/lib/schemas/booleanString.ts
|
|
60
|
+
* `booleanString` schema} from `@clipboard-health/contract-core`.
|
|
61
|
+
* 2. The resulting configuration is deeply frozen and will throw a runtime error if you attempt to
|
|
62
|
+
* modify it. The actual return type is `ReadonlyDeep<SchemaT>`, but the library returns a
|
|
63
|
+
* `Readonly<SchemaT>` because the former prevents clients from passing configuration values to
|
|
64
|
+
* functions that don't explicitly accept `readonly` types.
|
|
65
|
+
*
|
|
66
|
+
* @includeExample ./packages/config/examples/config.ts
|
|
67
|
+
* @see [Usage example](../../examples/config.ts)
|
|
68
|
+
*
|
|
69
|
+
* @throws {Error} When configuration values fail schema validation
|
|
70
|
+
* @returns A deeply frozen configuration object matching the provided schema
|
|
71
|
+
*/
|
|
72
|
+
export function createConfig<
|
|
73
|
+
const SchemaT extends Record<string, unknown>,
|
|
74
|
+
const EnvironmentT extends readonly string[],
|
|
75
|
+
>(params: Readonly<ConfigParams<SchemaT, EnvironmentT>>): Readonly<SchemaT> {
|
|
76
|
+
const { config, environment, schema } = params;
|
|
77
|
+
const { current } = environment;
|
|
78
|
+
|
|
79
|
+
const result = schema.safeParse(resolve({ config, environment: current, path: [], schema }));
|
|
80
|
+
if (!result.success) {
|
|
81
|
+
throw new Error(`Configuration validation failed: ${fromZodError(result.error).toString()}`, {
|
|
82
|
+
cause: result.error,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return deepFreeze(result.data);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A usage example:
|
|
23
92
|
|
|
24
93
|
<!-- prettier-ignore -->
|
|
25
94
|
```ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/config",
|
|
3
3
|
"description": "Type-safe static configuration management: a pure function to resolve, validate against a Zod schema, and freeze configuration values.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"decamelize": "5.0.1",
|
|
7
7
|
"tslib": "2.8.0",
|
package/src/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./lib/
|
|
1
|
+
export * from "./lib/createConfig";
|
|
2
2
|
export * from "./lib/types";
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./lib/
|
|
4
|
+
tslib_1.__exportStar(require("./lib/createConfig"), exports);
|
|
5
5
|
tslib_1.__exportStar(require("./lib/types"), exports);
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/config/src/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/config/src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAmC;AACnC,sDAA4B"}
|
|
@@ -47,8 +47,10 @@ function createConfig(params) {
|
|
|
47
47
|
const { current } = environment;
|
|
48
48
|
const result = schema.safeParse((0, resolver_1.resolve)({ config, environment: current, path: [], schema }));
|
|
49
49
|
if (!result.success) {
|
|
50
|
-
throw new Error((0, zod_validation_error_1.fromZodError)(result.error).toString()
|
|
50
|
+
throw new Error(`Configuration validation failed: ${(0, zod_validation_error_1.fromZodError)(result.error).toString()}`, {
|
|
51
|
+
cause: result.error,
|
|
52
|
+
});
|
|
51
53
|
}
|
|
52
54
|
return (0, deepFreeze_1.deepFreeze)(result.data);
|
|
53
55
|
}
|
|
54
|
-
//# sourceMappingURL=
|
|
56
|
+
//# sourceMappingURL=createConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createConfig.js","sourceRoot":"","sources":["../../../../../packages/config/src/lib/createConfig.ts"],"names":[],"mappings":";;AA4CA,oCAeC;AA3DD,+DAAoD;AAEpD,sDAAmD;AACnD,kDAA8C;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,SAAgB,YAAY,CAG1B,MAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IAEhC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAA,kBAAO,EAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAA,mCAAY,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE;YAC3F,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAA,uBAAU,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
|
package/src/lib/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../packages/config/src/lib/config.ts"],"names":[],"mappings":";;AA4CA,oCAaC;AAzDD,+DAAoD;AAEpD,sDAAmD;AACnD,kDAA8C;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,SAAgB,YAAY,CAG1B,MAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IAEhC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAA,kBAAO,EAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,IAAA,mCAAY,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,IAAA,uBAAU,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
|
|
File without changes
|