@arki/env 0.0.5 → 0.0.7
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/dist/core/define-env.d.ts.map +1 -1
- package/dist/core/define-env.js +55 -44
- package/dist/core/define-env.js.map +1 -1
- package/dist/dot.d.ts +7 -7
- package/dist/dot.d.ts.map +1 -1
- package/dist/dot.js +6 -6
- package/dist/dot.js.map +1 -1
- package/package.json +3 -2
- package/src/core/define-env.ts +61 -50
- package/src/dot.ts +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-env.d.ts","sourceRoot":"","sources":["../../src/core/define-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"define-env.d.ts","sourceRoot":"","sources":["../../src/core/define-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAEnC,qGAAqG;AACrG,KAAK,gBAAgB,GAAG,UAAU,CAChC,WAAW,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAClE,CAAC,CAAC,CAAC,CAAC;AAkBL;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,EAC9D,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,EAC9D,KAAK,CAAC,OAAO,SAAS,MAAM,GAAG,EAAE,EACjC,KAAK,CAAC,QAAQ,SAAS,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAC1D,MAAM,EAAE;IACR;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wFAAwF;IACxF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,qFAAqF;IACrF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB;;;;WAIG;QACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,KAAK,CAAC;KACzD,CAAC;CACH,GAAG,SAAS,CAAC,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAkExE"}
|
package/dist/core/define-env.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createEnv } from '@t3-oss/env-core';
|
|
2
|
+
import { lazyObject } from '@arki/ts';
|
|
2
3
|
/**
|
|
3
4
|
* Fold validation issues into a human-legible, log-pipeline-safe string. The t3-oss default handler
|
|
4
5
|
* logs `issues` as a raw object, which platforms like Coolify collapse to `[Object]` — so the var
|
|
@@ -25,52 +26,62 @@ function formatIssues(name, issues) {
|
|
|
25
26
|
* server key collapse to a type-level `ErrorMessage`, so the prefix must stay a literal.
|
|
26
27
|
*/
|
|
27
28
|
export function defineEnv(config) {
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
runtimeEnv
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
// LAZY by design: reading `process.env` and running validation are deferred
|
|
30
|
+
// to the FIRST property access, not the module import. Declaring an env is
|
|
31
|
+
// therefore observationally free — an app's declaration graph (features,
|
|
32
|
+
// adapters, `dot explain`, docs tooling) imports from a bare checkout with
|
|
33
|
+
// zero environment, and validation fires exactly when a value is actually
|
|
34
|
+
// consumed (boot, a request, a job). This is the same import/observe split
|
|
35
|
+
// drizzle tables have: define everywhere, observe only at use.
|
|
36
|
+
const build = () => {
|
|
37
|
+
const skipValidation = config.options?.skipValidation ?? (!!process.env.CI || process.env.NODE_ENV !== 'development');
|
|
38
|
+
// Use the caller's explicit runtimeEnv when supplied (Vite client vars via import.meta.env, or
|
|
39
|
+
// fallback aliases). Otherwise auto-build from every declared key (server + client + shared);
|
|
40
|
+
// createEnv tolerates keys absent from process.env (they parse as undefined → optional/default).
|
|
41
|
+
let runtimeEnv;
|
|
42
|
+
if (config.runtimeEnv) {
|
|
43
|
+
runtimeEnv = config.runtimeEnv;
|
|
40
44
|
}
|
|
41
|
-
|
|
42
|
-
runtimeEnv
|
|
45
|
+
else {
|
|
46
|
+
runtimeEnv = {};
|
|
47
|
+
for (const key of Object.keys(config.server)) {
|
|
48
|
+
runtimeEnv[key] = process.env[key];
|
|
49
|
+
}
|
|
50
|
+
for (const key of Object.keys(config.client ?? {})) {
|
|
51
|
+
runtimeEnv[key] = process.env[key];
|
|
52
|
+
}
|
|
53
|
+
for (const key of Object.keys(config.shared ?? {})) {
|
|
54
|
+
runtimeEnv[key] = process.env[key];
|
|
55
|
+
}
|
|
43
56
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
emptyStringAsUndefined: config.options?.emptyStringAsUndefined ?? true,
|
|
72
|
-
onValidationError,
|
|
57
|
+
const onValidationError = config.options?.onValidationError ??
|
|
58
|
+
((issues) => {
|
|
59
|
+
const message = formatIssues(config.name, issues);
|
|
60
|
+
console.error(message);
|
|
61
|
+
throw new Error(message);
|
|
62
|
+
});
|
|
63
|
+
// `createEnv`'s `server`/`client` params are conditional on `clientPrefix` being a *concrete*
|
|
64
|
+
// string literal; inside a generic wrapper `TPrefix` is abstract, so the body cannot be verified
|
|
65
|
+
// for all prefixes and the call argument must be asserted once. The PUBLIC contract stays exact:
|
|
66
|
+
// the explicit return type above reconstructs `createEnv`'s own result from the generics, and the
|
|
67
|
+
// caller's `server`/`client`/`extends` are fully type-checked against `TServer`/`TClient`/`TExtends`
|
|
68
|
+
// at the call site. This is the only seam where types are asserted — value types are never widened.
|
|
69
|
+
const options = {
|
|
70
|
+
shared: config.shared ?? {},
|
|
71
|
+
extends: config.extends,
|
|
72
|
+
server: config.server,
|
|
73
|
+
client: config.client ?? {},
|
|
74
|
+
clientPrefix: config.clientPrefix ?? '',
|
|
75
|
+
runtimeEnv,
|
|
76
|
+
skipValidation,
|
|
77
|
+
// Default ON: in containerized deploys an unset var is baked as "" (e.g. Docker `ENV X=${X}`
|
|
78
|
+
// with no build arg), not left absent. Treating "" as undefined lets `.default()`/`.optional()`
|
|
79
|
+
// apply as intended instead of failing format checks like `z.url()` on an empty string.
|
|
80
|
+
emptyStringAsUndefined: config.options?.emptyStringAsUndefined ?? true,
|
|
81
|
+
onValidationError,
|
|
82
|
+
};
|
|
83
|
+
return createEnv(options);
|
|
73
84
|
};
|
|
74
|
-
return
|
|
85
|
+
return lazyObject(build);
|
|
75
86
|
}
|
|
76
87
|
//# sourceMappingURL=define-env.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-env.js","sourceRoot":"","sources":["../../src/core/define-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"define-env.js","sourceRoot":"","sources":["../../src/core/define-env.ts"],"names":[],"mappings":"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"}
|
package/dist/dot.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DOT adapter for `@arki/env`.
|
|
3
3
|
*
|
|
4
|
-
* Wraps `defineEnv()` as a DOT
|
|
5
|
-
* environment alongside any other services. The
|
|
4
|
+
* Wraps `defineEnv()` as a DOT plugin so a DOT app can validate its
|
|
5
|
+
* environment alongside any other services. The plugin is sync (env
|
|
6
6
|
* validation is sync), so the `boot` hook returns the validated env
|
|
7
7
|
* object synchronously through the standard provides channel.
|
|
8
8
|
*
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* this adapter without `@arki/dot` installed will fail at module load —
|
|
34
34
|
* that is intentional: the adapter only makes sense in a DOT app.
|
|
35
35
|
*/
|
|
36
|
-
import { type EmptyShape, type
|
|
36
|
+
import { type EmptyShape, type Plugin } from '@arki/dot/plugin';
|
|
37
37
|
import type { ZodType } from 'zod';
|
|
38
38
|
/**
|
|
39
39
|
* Options for the env DOT adapter.
|
|
@@ -42,7 +42,7 @@ import type { ZodType } from 'zod';
|
|
|
42
42
|
* resulting `app.services.env` is typed from this.
|
|
43
43
|
*/
|
|
44
44
|
export type EnvDotOptions<TSchema extends Record<string, ZodType>> = {
|
|
45
|
-
/** Zod schemas for each env var the
|
|
45
|
+
/** Zod schemas for each env var the plugin validates. */
|
|
46
46
|
readonly schema: TSchema;
|
|
47
47
|
/**
|
|
48
48
|
* Forwarded to `defineEnv`. If `true`, the validator is skipped
|
|
@@ -58,10 +58,10 @@ export type EnvServices<TSchema extends Record<string, ZodType>> = {
|
|
|
58
58
|
};
|
|
59
59
|
};
|
|
60
60
|
/**
|
|
61
|
-
* Build a DOT
|
|
61
|
+
* Build a DOT plugin that validates and publishes a typed `env` service.
|
|
62
62
|
*
|
|
63
63
|
* @param options - Schema + optional config.
|
|
64
|
-
* @returns A
|
|
64
|
+
* @returns A plugin that publishes `services.env`.
|
|
65
65
|
*/
|
|
66
|
-
export declare function env<TSchema extends Record<string, ZodType>>(options: EnvDotOptions<TSchema>):
|
|
66
|
+
export declare function env<TSchema extends Record<string, ZodType>>(options: EnvDotOptions<TSchema>): Plugin<EmptyShape, EnvServices<TSchema>>;
|
|
67
67
|
//# sourceMappingURL=dot.d.ts.map
|
package/dist/dot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAU,KAAK,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAInC;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACnE,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACjE,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;KAAE,CAAC;CAClG,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzD,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAC9B,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAuB1C"}
|
package/dist/dot.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DOT adapter for `@arki/env`.
|
|
3
3
|
*
|
|
4
|
-
* Wraps `defineEnv()` as a DOT
|
|
5
|
-
* environment alongside any other services. The
|
|
4
|
+
* Wraps `defineEnv()` as a DOT plugin so a DOT app can validate its
|
|
5
|
+
* environment alongside any other services. The plugin is sync (env
|
|
6
6
|
* validation is sync), so the `boot` hook returns the validated env
|
|
7
7
|
* object synchronously through the standard provides channel.
|
|
8
8
|
*
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
* this adapter without `@arki/dot` installed will fail at module load —
|
|
34
34
|
* that is intentional: the adapter only makes sense in a DOT app.
|
|
35
35
|
*/
|
|
36
|
-
import {
|
|
36
|
+
import { plugin } from '@arki/dot/plugin';
|
|
37
37
|
import { defineEnv } from './core/define-env.js';
|
|
38
38
|
/**
|
|
39
|
-
* Build a DOT
|
|
39
|
+
* Build a DOT plugin that validates and publishes a typed `env` service.
|
|
40
40
|
*
|
|
41
41
|
* @param options - Schema + optional config.
|
|
42
|
-
* @returns A
|
|
42
|
+
* @returns A plugin that publishes `services.env`.
|
|
43
43
|
*/
|
|
44
44
|
export function env(options) {
|
|
45
|
-
return
|
|
45
|
+
return plugin({
|
|
46
46
|
name: 'env',
|
|
47
47
|
version: '0.1.0',
|
|
48
48
|
configure(ctx) {
|
package/dist/dot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.js","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"dot.js","sourceRoot":"","sources":["../src/dot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,MAAM,EAAgC,MAAM,kBAAkB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAwBjD;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CACjB,OAA+B;IAE/B,OAAO,MAAM,CAAC;QACZ,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,OAAO;QAChB,SAAS,CAAC,GAAG;YACX,GAAG,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,IAAI;YACF,MAAM,SAAS,GAAG,SAAS,CAAC;gBAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EACL,OAAO,CAAC,cAAc,KAAK,SAAS;oBAClC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE;oBAC5C,CAAC,CAAC,SAAS;aAChB,CAAC,CAAC;YACH,oEAAoE;YACpE,kEAAkE;YAClE,8DAA8D;YAC9D,0DAA0D;YAC1D,MAAM,SAAS,GAAG,SAAmD,CAAC;YACtE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;QAC5B,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arki/env",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Type-safe environment variable parsing for ARKI — defineEnv() built on @t3-oss/env-core with Zod contracts for common variable shapes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,11 +58,12 @@
|
|
|
58
58
|
"package.json"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
+
"@arki/ts": "0.0.3",
|
|
61
62
|
"@t3-oss/env-core": "^0.13.10",
|
|
62
63
|
"zod": "4.3.5"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
|
-
"@arki/dot": "^0.
|
|
66
|
+
"@arki/dot": "^0.4.0"
|
|
66
67
|
},
|
|
67
68
|
"peerDependenciesMeta": {
|
|
68
69
|
"@arki/dot": {
|
package/src/core/define-env.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createEnv } from '@t3-oss/env-core';
|
|
2
2
|
import type { CreateEnv, DefaultCombinedSchema } from '@t3-oss/env-core';
|
|
3
|
+
import { lazyObject } from '@arki/ts';
|
|
3
4
|
import type { ZodType } from 'zod';
|
|
4
5
|
|
|
5
6
|
/** The issue shape t3-oss hands to `onValidationError`, derived so it stays in sync with the lib. */
|
|
@@ -76,59 +77,69 @@ export function defineEnv<
|
|
|
76
77
|
onValidationError?: (issues: ValidationIssues) => never;
|
|
77
78
|
};
|
|
78
79
|
}): CreateEnv<DefaultCombinedSchema<TServer, TClient, TShared>, TExtends> {
|
|
79
|
-
|
|
80
|
-
config.options?.skipValidation ?? (!!process.env.CI || process.env.NODE_ENV !== 'development');
|
|
80
|
+
type Result = CreateEnv<DefaultCombinedSchema<TServer, TClient, TShared>, TExtends>;
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
82
|
+
// LAZY by design: reading `process.env` and running validation are deferred
|
|
83
|
+
// to the FIRST property access, not the module import. Declaring an env is
|
|
84
|
+
// therefore observationally free — an app's declaration graph (features,
|
|
85
|
+
// adapters, `dot explain`, docs tooling) imports from a bare checkout with
|
|
86
|
+
// zero environment, and validation fires exactly when a value is actually
|
|
87
|
+
// consumed (boot, a request, a job). This is the same import/observe split
|
|
88
|
+
// drizzle tables have: define everywhere, observe only at use.
|
|
89
|
+
const build = (): Result => {
|
|
90
|
+
const skipValidation =
|
|
91
|
+
config.options?.skipValidation ?? (!!process.env.CI || process.env.NODE_ENV !== 'development');
|
|
92
|
+
|
|
93
|
+
// Use the caller's explicit runtimeEnv when supplied (Vite client vars via import.meta.env, or
|
|
94
|
+
// fallback aliases). Otherwise auto-build from every declared key (server + client + shared);
|
|
95
|
+
// createEnv tolerates keys absent from process.env (they parse as undefined → optional/default).
|
|
96
|
+
let runtimeEnv: Record<string, string | boolean | number | undefined>;
|
|
97
|
+
if (config.runtimeEnv) {
|
|
98
|
+
runtimeEnv = config.runtimeEnv;
|
|
99
|
+
} else {
|
|
100
|
+
runtimeEnv = {};
|
|
101
|
+
for (const key of Object.keys(config.server)) {
|
|
102
|
+
runtimeEnv[key] = process.env[key];
|
|
103
|
+
}
|
|
104
|
+
for (const key of Object.keys(config.client ?? {})) {
|
|
105
|
+
runtimeEnv[key] = process.env[key];
|
|
106
|
+
}
|
|
107
|
+
for (const key of Object.keys(config.shared ?? {})) {
|
|
108
|
+
runtimeEnv[key] = process.env[key];
|
|
109
|
+
}
|
|
98
110
|
}
|
|
99
|
-
}
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
const onValidationError =
|
|
113
|
+
config.options?.onValidationError ??
|
|
114
|
+
((issues: ValidationIssues): never => {
|
|
115
|
+
const message = formatIssues(config.name, issues);
|
|
116
|
+
console.error(message);
|
|
117
|
+
throw new Error(message);
|
|
118
|
+
});
|
|
108
119
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
// `createEnv`'s `server`/`client` params are conditional on `clientPrefix` being a *concrete*
|
|
121
|
+
// string literal; inside a generic wrapper `TPrefix` is abstract, so the body cannot be verified
|
|
122
|
+
// for all prefixes and the call argument must be asserted once. The PUBLIC contract stays exact:
|
|
123
|
+
// the explicit return type above reconstructs `createEnv`'s own result from the generics, and the
|
|
124
|
+
// caller's `server`/`client`/`extends` are fully type-checked against `TServer`/`TClient`/`TExtends`
|
|
125
|
+
// at the call site. This is the only seam where types are asserted — value types are never widened.
|
|
126
|
+
const options = {
|
|
127
|
+
shared: config.shared ?? {},
|
|
128
|
+
extends: config.extends,
|
|
129
|
+
server: config.server,
|
|
130
|
+
client: config.client ?? {},
|
|
131
|
+
clientPrefix: config.clientPrefix ?? '',
|
|
132
|
+
runtimeEnv,
|
|
133
|
+
skipValidation,
|
|
134
|
+
// Default ON: in containerized deploys an unset var is baked as "" (e.g. Docker `ENV X=${X}`
|
|
135
|
+
// with no build arg), not left absent. Treating "" as undefined lets `.default()`/`.optional()`
|
|
136
|
+
// apply as intended instead of failing format checks like `z.url()` on an empty string.
|
|
137
|
+
emptyStringAsUndefined: config.options?.emptyStringAsUndefined ?? true,
|
|
138
|
+
onValidationError,
|
|
139
|
+
} satisfies Record<string, unknown>;
|
|
140
|
+
|
|
141
|
+
return createEnv(options as Parameters<typeof createEnv>[0]) as Result;
|
|
142
|
+
};
|
|
129
143
|
|
|
130
|
-
return
|
|
131
|
-
DefaultCombinedSchema<TServer, TClient, TShared>,
|
|
132
|
-
TExtends
|
|
133
|
-
>;
|
|
144
|
+
return lazyObject(build);
|
|
134
145
|
}
|
package/src/dot.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DOT adapter for `@arki/env`.
|
|
3
3
|
*
|
|
4
|
-
* Wraps `defineEnv()` as a DOT
|
|
5
|
-
* environment alongside any other services. The
|
|
4
|
+
* Wraps `defineEnv()` as a DOT plugin so a DOT app can validate its
|
|
5
|
+
* environment alongside any other services. The plugin is sync (env
|
|
6
6
|
* validation is sync), so the `boot` hook returns the validated env
|
|
7
7
|
* object synchronously through the standard provides channel.
|
|
8
8
|
*
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* that is intentional: the adapter only makes sense in a DOT app.
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
import {
|
|
37
|
+
import { plugin, type EmptyShape, type Plugin } from '@arki/dot/plugin';
|
|
38
38
|
import type { ZodType } from 'zod';
|
|
39
39
|
|
|
40
40
|
import { defineEnv } from './core/define-env.js';
|
|
@@ -46,7 +46,7 @@ import { defineEnv } from './core/define-env.js';
|
|
|
46
46
|
* resulting `app.services.env` is typed from this.
|
|
47
47
|
*/
|
|
48
48
|
export type EnvDotOptions<TSchema extends Record<string, ZodType>> = {
|
|
49
|
-
/** Zod schemas for each env var the
|
|
49
|
+
/** Zod schemas for each env var the plugin validates. */
|
|
50
50
|
readonly schema: TSchema;
|
|
51
51
|
/**
|
|
52
52
|
* Forwarded to `defineEnv`. If `true`, the validator is skipped
|
|
@@ -62,15 +62,15 @@ export type EnvServices<TSchema extends Record<string, ZodType>> = {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Build a DOT
|
|
65
|
+
* Build a DOT plugin that validates and publishes a typed `env` service.
|
|
66
66
|
*
|
|
67
67
|
* @param options - Schema + optional config.
|
|
68
|
-
* @returns A
|
|
68
|
+
* @returns A plugin that publishes `services.env`.
|
|
69
69
|
*/
|
|
70
70
|
export function env<TSchema extends Record<string, ZodType>>(
|
|
71
71
|
options: EnvDotOptions<TSchema>,
|
|
72
|
-
):
|
|
73
|
-
return
|
|
72
|
+
): Plugin<EmptyShape, EnvServices<TSchema>> {
|
|
73
|
+
return plugin({
|
|
74
74
|
name: 'env',
|
|
75
75
|
version: '0.1.0',
|
|
76
76
|
configure(ctx) {
|