@penvhq/runtime 0.3.1 → 0.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/dist/index.cjs +35 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +36 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -107,6 +107,12 @@ function place(root, path, value) {
|
|
|
107
107
|
node[leaf] = value;
|
|
108
108
|
}
|
|
109
109
|
function load(schema, options) {
|
|
110
|
+
if ((0, import_core2.schemaHarvestActive)()) {
|
|
111
|
+
return deferLoad(schema, options);
|
|
112
|
+
}
|
|
113
|
+
return loadEagerly(schema, options);
|
|
114
|
+
}
|
|
115
|
+
function loadEagerly(schema, options) {
|
|
110
116
|
const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);
|
|
111
117
|
const object = {};
|
|
112
118
|
for (const { ref, value } of values) {
|
|
@@ -124,6 +130,35 @@ function load(schema, options) {
|
|
|
124
130
|
}
|
|
125
131
|
return result.data;
|
|
126
132
|
}
|
|
133
|
+
function deferLoad(schema, options) {
|
|
134
|
+
let materialized = false;
|
|
135
|
+
let value;
|
|
136
|
+
const materialize = () => {
|
|
137
|
+
if (!materialized) {
|
|
138
|
+
value = loadEagerly(schema, options);
|
|
139
|
+
materialized = true;
|
|
140
|
+
}
|
|
141
|
+
return Object(value);
|
|
142
|
+
};
|
|
143
|
+
return new Proxy({}, {
|
|
144
|
+
get(_target, property) {
|
|
145
|
+
if ((0, import_core2.schemaHarvestActive)() && (typeof property === "symbol" || property === "then")) {
|
|
146
|
+
return void 0;
|
|
147
|
+
}
|
|
148
|
+
return Reflect.get(materialize(), property);
|
|
149
|
+
},
|
|
150
|
+
has(_target, property) {
|
|
151
|
+
return Reflect.has(materialize(), property);
|
|
152
|
+
},
|
|
153
|
+
ownKeys() {
|
|
154
|
+
return Reflect.ownKeys(materialize());
|
|
155
|
+
},
|
|
156
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
157
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(materialize(), property);
|
|
158
|
+
return descriptor === void 0 ? void 0 : { ...descriptor, configurable: true };
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
127
162
|
// Annotate the CommonJS export names for ESM import in node:
|
|
128
163
|
0 && (module.exports = {
|
|
129
164
|
ConfigError,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/load.ts","../src/resolve.ts"],"sourcesContent":["/**\n * The public surface of `@penvhq/runtime` — what `penv` re-exports.\n *\n * `defineConfig` is re-exported from `@penvhq/core` because the docs show\n * `penv.config.ts` importing it from `penv`: one import specifier for the whole\n * tool, whatever package a symbol happens to live in.\n */\n\nexport {\n ConfigError,\n defineConfig,\n FilenameGrammarError,\n MissingParameterError,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n UnknownEnvironmentError,\n ValidationError,\n} from \"@penvhq/core\";\nexport type { LoadOptions } from \"./load.js\";\nexport { load } from \"./load.js\";\n","/**\n * The runtime loader. `load` is generic and returns `z.infer<T>` — the type the\n * caller's own schema describes, never a widened one. The inferred type is only\n * true because the same schema validates the values before they are returned,\n * so the type you code against and the value you receive cannot diverge.\n */\n\nimport { accessPath, ValidationError } from \"@penvhq/core\";\nimport type { z } from \"zod\";\nimport { resolveSync } from \"./resolve.js\";\n\nexport interface LoadOptions {\n /** Where to start looking for `penv.config.ts`. Defaults to `process.cwd()`. */\n readonly cwd?: string;\n /** Overrides `PENV_ENV` / `NODE_ENV`. Must be a declared environment. */\n readonly environment?: string;\n}\n\n/**\n * Places a value at its access path, creating namespaces on the way.\n * Values are placed exactly as the provider holds them: coercion is the\n * schema's job, so a value file's contents stay a string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\n/**\n * Loads, validates, and returns configuration for the current environment.\n * Eager and synchronous: invalid configuration fails at startup with a\n * parameter-named error rather than later at first use.\n */\nexport function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);\n\n const object: Record<string, unknown> = {};\n for (const { ref, value } of values) {\n place(object, accessPath(ref), value);\n }\n\n const result = schema.safeParse(object);\n if (!result.success) {\n throw new ValidationError(\n environment,\n result.error.issues.map((issue) => ({\n parameter: issue.path.join(\".\"),\n message: issue.message,\n })),\n );\n }\n return result.data;\n}\n","/**\n * The synchronous half of the value cascade, shared by `load` and the\n * `penv/config` compatibility entry.\n *\n * `resolveParameter` in `@penvhq/core` is async because the provider contract is,\n * and `load` is synchronous — so this module walks the cascade against the\n * filesystem provider's synchronous reads instead. It does not restate the\n * precedence rule: `candidatesFor` owns the order and everything here only\n * walks the list it returns, so the two paths cannot drift apart.\n *\n * The runtime reads the local tree for every environment, whatever provider\n * that environment declares, and this is the design rather than a limitation.\n * A provider is where an environment's source of truth *lives*, not where the\n * runtime reads from: `penv pull` materialises the tree from the provider, and\n * the runtime then reads what is on disk. So `load` never inspects\n * `providers.*.type` — a Vault-backed environment resolves through exactly the\n * code path a filesystem-backed one does, which is what makes changing provider\n * a configuration change rather than an application rewrite.\n *\n * Decryption happens here, synchronously, and that is the same knife applied a\n * second time. Key *acquisition* is async and happens before the process starts:\n * a deploy unwraps the KMS-derived data key and exports it, exactly as it already\n * runs `penv pull` to materialise the tree. Key *use* is a synchronous pure\n * function over bytes. penv never calls a KMS in-process — a key is where an\n * environment's secret material *lives*, not what the runtime dials at boot, just\n * as a provider is a sync target and not a runtime source. So invariant 3 is not\n * traded against encryption: `load` stays generic and synchronous because the\n * network half of both problems was moved out of the process entirely, rather\n * than awaited inside it.\n */\n\nimport { dirname, resolve as resolvePath } from \"node:path\";\nimport type { ParameterRef, PenvConfig, ValueFile } from \"@penvhq/core\";\nimport {\n candidatesFor,\n formatValueFile,\n loadConfig,\n openValue,\n parameterId,\n resolveEnvironment,\n resolveKeySource,\n UndecryptableValueError,\n} from \"@penvhq/core\";\nimport { createFilesystemProvider } from \"@penvhq/provider-filesystem\";\n\n/** One parameter that resolved to a present value for the target environment. */\nexport interface ResolvedValue {\n readonly ref: ParameterRef;\n readonly value: string;\n}\n\nexport interface ResolvedConfig {\n readonly config: PenvConfig;\n readonly environment: string;\n /**\n * Only parameters with a present candidate. A parameter that resolved to\n * nothing is absent rather than `undefined`, so requiredness stays the\n * schema's call.\n */\n readonly values: readonly ResolvedValue[];\n}\n\n/**\n * The parameters behind a set of value files, scopes collapsed —\n * `redis/password.production` and `redis/password` are one parameter. Ordered\n * so a `process.env` population is identical on every machine.\n */\nfunction refsFrom(files: readonly ValueFile[]): ParameterRef[] {\n const refs = new Map<string, ParameterRef>();\n for (const file of files) {\n const ref: ParameterRef = { namespace: file.namespace, name: file.name };\n const id = parameterId(ref);\n if (!refs.has(id)) {\n refs.set(id, ref);\n }\n }\n return [...refs.values()].sort((a, b) => {\n const left = parameterId(a);\n const right = parameterId(b);\n return left < right ? -1 : left > right ? 1 : 0;\n });\n}\n\n/**\n * Loads the config, settles the environment, and resolves every parameter the\n * local tree holds — the work `load` and `penv/config` both start from.\n */\nexport function resolveSync(cwd: string, environment?: string): ResolvedConfig {\n const { config, file } = loadConfig(cwd);\n const target = resolveEnvironment(config, environment);\n\n const provider = createFilesystemProvider({\n root: resolvePath(dirname(file), \".penv\"),\n config,\n });\n\n const keys = resolveKeySource(config, target);\n\n const values: ResolvedValue[] = [];\n for (const ref of refsFrom(provider.listSync())) {\n for (const candidate of candidatesFor(ref, target)) {\n const read = provider.readSync(candidate);\n if (read === undefined) {\n continue;\n }\n // The winner is the winner whether or not it opens. Continuing the walk on\n // a failed decrypt would serve a lower scope's plaintext twin instead —\n // the scope widening the cascade exists to prevent, arrived at by treating\n // \"I cannot read this\" as \"this is not here\".\n const opened = openValue(candidate, read, keys);\n if (opened.kind === \"failed\") {\n throw new UndecryptableValueError(\n parameterId(ref),\n target,\n formatValueFile(candidate),\n opened.failure,\n );\n }\n values.push({ ref, value: opened.value });\n break;\n }\n }\n\n return { config, environment: target, values };\n}\n"],"mappings":"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","names":["import_core","import_core","resolvePath"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/load.ts","../src/resolve.ts"],"sourcesContent":["/**\n * The public surface of `@penvhq/runtime` — what `penv` re-exports.\n *\n * `defineConfig` is re-exported from `@penvhq/core` because the docs show\n * `penv.config.ts` importing it from `penv`: one import specifier for the whole\n * tool, whatever package a symbol happens to live in.\n */\n\nexport {\n ConfigError,\n defineConfig,\n FilenameGrammarError,\n MissingParameterError,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n UnknownEnvironmentError,\n ValidationError,\n} from \"@penvhq/core\";\nexport type { LoadOptions } from \"./load.js\";\nexport { load } from \"./load.js\";\n","/**\n * The runtime loader. `load` is generic and returns `z.infer<T>` — the type the\n * caller's own schema describes, never a widened one. The inferred type is only\n * true because the same schema validates the values before they are returned,\n * so the type you code against and the value you receive cannot diverge.\n */\n\nimport { accessPath, schemaHarvestActive, ValidationError } from \"@penvhq/core\";\nimport type { z } from \"zod\";\nimport { resolveSync } from \"./resolve.js\";\n\nexport interface LoadOptions {\n /** Where to start looking for `penv.config.ts`. Defaults to `process.cwd()`. */\n readonly cwd?: string;\n /** Overrides `PENV_ENV` / `NODE_ENV`. Must be a declared environment. */\n readonly environment?: string;\n}\n\n/**\n * Places a value at its access path, creating namespaces on the way.\n * Values are placed exactly as the provider holds them: coercion is the\n * schema's job, so a value file's contents stay a string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\n/**\n * Loads, validates, and returns configuration for the current environment.\n * Eager and synchronous: invalid configuration fails at startup with a\n * parameter-named error rather than later at first use.\n *\n * One deliberate exception to the eagerness: while the CLI is harvesting the\n * `schema` export of `.penv/env.ts` (see `SCHEMA_HARVEST_ENV` in core), the\n * scaffolded module's own `export const env = load(schema)` must not stop the\n * module from evaluating — an empty tree would throw here and take the `schema`\n * export down with it, which is exactly the state `penv fill` exists to fix. In\n * that window `load` returns a lazy stand-in that performs the real load — and\n * raises the same parameter-named error — on first property access. Application\n * runtime never sets the flag, so ordinary loads stay eager and fail-fast.\n */\nexport function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n if (schemaHarvestActive()) {\n return deferLoad(schema, options);\n }\n return loadEagerly(schema, options);\n}\n\nfunction loadEagerly<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);\n\n const object: Record<string, unknown> = {};\n for (const { ref, value } of values) {\n place(object, accessPath(ref), value);\n }\n\n const result = schema.safeParse(object);\n if (!result.success) {\n throw new ValidationError(\n environment,\n result.error.issues.map((issue) => ({\n parameter: issue.path.join(\".\"),\n message: issue.message,\n })),\n );\n }\n return result.data;\n}\n\n/**\n * `load`'s harvest-time stand-in: nothing is resolved or validated until a\n * property is actually read. The schema module's top level only *binds*\n * `export const env`, so under harvest the binding succeeds, the CLI reads the\n * `schema` export, and the deferred error — if the tree still cannot satisfy the\n * schema — surfaces on first real use with the same `ValidationError` the eager\n * path throws.\n */\nfunction deferLoad<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n let materialized = false;\n let value: unknown;\n const materialize = (): object => {\n if (!materialized) {\n value = loadEagerly(schema, options);\n materialized = true;\n }\n // `Object(...)` keeps the traps total even for a schema whose root is not an\n // object — property reads then forward to the boxed primitive.\n return Object(value);\n };\n\n return new Proxy({} as Record<PropertyKey, unknown>, {\n get(_target, property) {\n // Module plumbing probes exported values while the harvest import is still\n // in flight — `then` (module namespaces are awaited by some loaders) and\n // well-known symbols (inspection). Those probes must not force the load;\n // real reads, which arrive after the harvest window closes, must.\n if (schemaHarvestActive() && (typeof property === \"symbol\" || property === \"then\")) {\n return undefined;\n }\n return Reflect.get(materialize(), property);\n },\n has(_target, property) {\n return Reflect.has(materialize(), property);\n },\n ownKeys() {\n return Reflect.ownKeys(materialize());\n },\n getOwnPropertyDescriptor(_target, property) {\n const descriptor = Reflect.getOwnPropertyDescriptor(materialize(), property);\n // Configurable, so the descriptor stays compatible with the empty proxy\n // target — the invariant check would throw for a frozen original otherwise.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true };\n },\n }) as z.infer<T>;\n}\n","/**\n * The synchronous half of the value cascade, shared by `load` and the\n * `penv/config` compatibility entry.\n *\n * `resolveParameter` in `@penvhq/core` is async because the provider contract is,\n * and `load` is synchronous — so this module walks the cascade against the\n * filesystem provider's synchronous reads instead. It does not restate the\n * precedence rule: `candidatesFor` owns the order and everything here only\n * walks the list it returns, so the two paths cannot drift apart.\n *\n * The runtime reads the local tree for every environment, whatever provider\n * that environment declares, and this is the design rather than a limitation.\n * A provider is where an environment's source of truth *lives*, not where the\n * runtime reads from: `penv pull` materialises the tree from the provider, and\n * the runtime then reads what is on disk. So `load` never inspects\n * `providers.*.type` — a Vault-backed environment resolves through exactly the\n * code path a filesystem-backed one does, which is what makes changing provider\n * a configuration change rather than an application rewrite.\n *\n * Decryption happens here, synchronously, and that is the same knife applied a\n * second time. Key *acquisition* is async and happens before the process starts:\n * a deploy unwraps the KMS-derived data key and exports it, exactly as it already\n * runs `penv pull` to materialise the tree. Key *use* is a synchronous pure\n * function over bytes. penv never calls a KMS in-process — a key is where an\n * environment's secret material *lives*, not what the runtime dials at boot, just\n * as a provider is a sync target and not a runtime source. So invariant 3 is not\n * traded against encryption: `load` stays generic and synchronous because the\n * network half of both problems was moved out of the process entirely, rather\n * than awaited inside it.\n */\n\nimport { dirname, resolve as resolvePath } from \"node:path\";\nimport type { ParameterRef, PenvConfig, ValueFile } from \"@penvhq/core\";\nimport {\n candidatesFor,\n formatValueFile,\n loadConfig,\n openValue,\n parameterId,\n resolveEnvironment,\n resolveKeySource,\n UndecryptableValueError,\n} from \"@penvhq/core\";\nimport { createFilesystemProvider } from \"@penvhq/provider-filesystem\";\n\n/** One parameter that resolved to a present value for the target environment. */\nexport interface ResolvedValue {\n readonly ref: ParameterRef;\n readonly value: string;\n}\n\nexport interface ResolvedConfig {\n readonly config: PenvConfig;\n readonly environment: string;\n /**\n * Only parameters with a present candidate. A parameter that resolved to\n * nothing is absent rather than `undefined`, so requiredness stays the\n * schema's call.\n */\n readonly values: readonly ResolvedValue[];\n}\n\n/**\n * The parameters behind a set of value files, scopes collapsed —\n * `redis/password.production` and `redis/password` are one parameter. Ordered\n * so a `process.env` population is identical on every machine.\n */\nfunction refsFrom(files: readonly ValueFile[]): ParameterRef[] {\n const refs = new Map<string, ParameterRef>();\n for (const file of files) {\n const ref: ParameterRef = { namespace: file.namespace, name: file.name };\n const id = parameterId(ref);\n if (!refs.has(id)) {\n refs.set(id, ref);\n }\n }\n return [...refs.values()].sort((a, b) => {\n const left = parameterId(a);\n const right = parameterId(b);\n return left < right ? -1 : left > right ? 1 : 0;\n });\n}\n\n/**\n * Loads the config, settles the environment, and resolves every parameter the\n * local tree holds — the work `load` and `penv/config` both start from.\n */\nexport function resolveSync(cwd: string, environment?: string): ResolvedConfig {\n const { config, file } = loadConfig(cwd);\n const target = resolveEnvironment(config, environment);\n\n const provider = createFilesystemProvider({\n root: resolvePath(dirname(file), \".penv\"),\n config,\n });\n\n const keys = resolveKeySource(config, target);\n\n const values: ResolvedValue[] = [];\n for (const ref of refsFrom(provider.listSync())) {\n for (const candidate of candidatesFor(ref, target)) {\n const read = provider.readSync(candidate);\n if (read === undefined) {\n continue;\n }\n // The winner is the winner whether or not it opens. Continuing the walk on\n // a failed decrypt would serve a lower scope's plaintext twin instead —\n // the scope widening the cascade exists to prevent, arrived at by treating\n // \"I cannot read this\" as \"this is not here\".\n const opened = openValue(candidate, read, keys);\n if (opened.kind === \"failed\") {\n throw new UndecryptableValueError(\n parameterId(ref),\n target,\n formatValueFile(candidate),\n opened.failure,\n );\n }\n values.push({ ref, value: opened.value });\n break;\n }\n }\n\n return { config, environment: target, values };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,IAAAA,eAUO;;;ACXP,IAAAC,eAAiE;;;ACwBjE,uBAAgD;AAEhD,kBASO;AACP,iCAAyC;AAwBzC,SAAS,SAAS,OAA6C;AAC7D,QAAM,OAAO,oBAAI,IAA0B;AAC3C,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAoB,EAAE,WAAW,KAAK,WAAW,MAAM,KAAK,KAAK;AACvE,UAAM,SAAK,yBAAY,GAAG;AAC1B,QAAI,CAAC,KAAK,IAAI,EAAE,GAAG;AACjB,WAAK,IAAI,IAAI,GAAG;AAAA,IAClB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,KAAK,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AACvC,UAAM,WAAO,yBAAY,CAAC;AAC1B,UAAM,YAAQ,yBAAY,CAAC;AAC3B,WAAO,OAAO,QAAQ,KAAK,OAAO,QAAQ,IAAI;AAAA,EAChD,CAAC;AACH;AAMO,SAAS,YAAY,KAAa,aAAsC;AAC7E,QAAM,EAAE,QAAQ,KAAK,QAAI,wBAAW,GAAG;AACvC,QAAM,aAAS,gCAAmB,QAAQ,WAAW;AAErD,QAAM,eAAW,qDAAyB;AAAA,IACxC,UAAM,iBAAAC,aAAY,0BAAQ,IAAI,GAAG,OAAO;AAAA,IACxC;AAAA,EACF,CAAC;AAED,QAAM,WAAO,8BAAiB,QAAQ,MAAM;AAE5C,QAAM,SAA0B,CAAC;AACjC,aAAW,OAAO,SAAS,SAAS,SAAS,CAAC,GAAG;AAC/C,eAAW,iBAAa,2BAAc,KAAK,MAAM,GAAG;AAClD,YAAM,OAAO,SAAS,SAAS,SAAS;AACxC,UAAI,SAAS,QAAW;AACtB;AAAA,MACF;AAKA,YAAM,aAAS,uBAAU,WAAW,MAAM,IAAI;AAC9C,UAAI,OAAO,SAAS,UAAU;AAC5B,cAAM,IAAI;AAAA,cACR,yBAAY,GAAG;AAAA,UACf;AAAA,cACA,6BAAgB,SAAS;AAAA,UACzB,OAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO,KAAK,EAAE,KAAK,OAAO,OAAO,MAAM,CAAC;AACxC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,aAAa,QAAQ,OAAO;AAC/C;;;ADrGA,SAAS,MAAM,MAA+B,MAAyB,OAAqB;AAC1F,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,MAAI,SAAS,QAAW;AACtB;AAAA,EACF;AAEA,MAAI,OAAO;AACX,aAAW,OAAO,KAAK,MAAM,GAAG,EAAE,GAAG;AACnC,UAAM,WAAW,KAAK,GAAG;AACzB,QAAI,OAAO,aAAa,YAAY,aAAa,MAAM;AACrD,aAAO;AACP;AAAA,IACF;AACA,UAAM,QAAiC,CAAC;AACxC,SAAK,GAAG,IAAI;AACZ,WAAO;AAAA,EACT;AACA,OAAK,IAAI,IAAI;AACf;AAgBO,SAAS,KAA0B,QAAW,SAAmC;AACtF,UAAI,kCAAoB,GAAG;AACzB,WAAO,UAAU,QAAQ,OAAO;AAAA,EAClC;AACA,SAAO,YAAY,QAAQ,OAAO;AACpC;AAEA,SAAS,YAAiC,QAAW,SAAmC;AACtF,QAAM,EAAE,aAAa,OAAO,IAAI,YAAY,SAAS,OAAO,QAAQ,IAAI,GAAG,SAAS,WAAW;AAE/F,QAAM,SAAkC,CAAC;AACzC,aAAW,EAAE,KAAK,MAAM,KAAK,QAAQ;AACnC,UAAM,YAAQ,yBAAW,GAAG,GAAG,KAAK;AAAA,EACtC;AAEA,QAAM,SAAS,OAAO,UAAU,MAAM;AACtC,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,QAClC,WAAW,MAAM,KAAK,KAAK,GAAG;AAAA,QAC9B,SAAS,MAAM;AAAA,MACjB,EAAE;AAAA,IACJ;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAUA,SAAS,UAA+B,QAAW,SAAmC;AACpF,MAAI,eAAe;AACnB,MAAI;AACJ,QAAM,cAAc,MAAc;AAChC,QAAI,CAAC,cAAc;AACjB,cAAQ,YAAY,QAAQ,OAAO;AACnC,qBAAe;AAAA,IACjB;AAGA,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,SAAO,IAAI,MAAM,CAAC,GAAmC;AAAA,IACnD,IAAI,SAAS,UAAU;AAKrB,cAAI,kCAAoB,MAAM,OAAO,aAAa,YAAY,aAAa,SAAS;AAClF,eAAO;AAAA,MACT;AACA,aAAO,QAAQ,IAAI,YAAY,GAAG,QAAQ;AAAA,IAC5C;AAAA,IACA,IAAI,SAAS,UAAU;AACrB,aAAO,QAAQ,IAAI,YAAY,GAAG,QAAQ;AAAA,IAC5C;AAAA,IACA,UAAU;AACR,aAAO,QAAQ,QAAQ,YAAY,CAAC;AAAA,IACtC;AAAA,IACA,yBAAyB,SAAS,UAAU;AAC1C,YAAM,aAAa,QAAQ,yBAAyB,YAAY,GAAG,QAAQ;AAG3E,aAAO,eAAe,SAAY,SAAY,EAAE,GAAG,YAAY,cAAc,KAAK;AAAA,IACpF;AAAA,EACF,CAAC;AACH;","names":["import_core","import_core","resolvePath"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -18,6 +18,15 @@ interface LoadOptions {
|
|
|
18
18
|
* Loads, validates, and returns configuration for the current environment.
|
|
19
19
|
* Eager and synchronous: invalid configuration fails at startup with a
|
|
20
20
|
* parameter-named error rather than later at first use.
|
|
21
|
+
*
|
|
22
|
+
* One deliberate exception to the eagerness: while the CLI is harvesting the
|
|
23
|
+
* `schema` export of `.penv/env.ts` (see `SCHEMA_HARVEST_ENV` in core), the
|
|
24
|
+
* scaffolded module's own `export const env = load(schema)` must not stop the
|
|
25
|
+
* module from evaluating — an empty tree would throw here and take the `schema`
|
|
26
|
+
* export down with it, which is exactly the state `penv fill` exists to fix. In
|
|
27
|
+
* that window `load` returns a lazy stand-in that performs the real load — and
|
|
28
|
+
* raises the same parameter-named error — on first property access. Application
|
|
29
|
+
* runtime never sets the flag, so ordinary loads stay eager and fail-fast.
|
|
21
30
|
*/
|
|
22
31
|
declare function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T>;
|
|
23
32
|
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,15 @@ interface LoadOptions {
|
|
|
18
18
|
* Loads, validates, and returns configuration for the current environment.
|
|
19
19
|
* Eager and synchronous: invalid configuration fails at startup with a
|
|
20
20
|
* parameter-named error rather than later at first use.
|
|
21
|
+
*
|
|
22
|
+
* One deliberate exception to the eagerness: while the CLI is harvesting the
|
|
23
|
+
* `schema` export of `.penv/env.ts` (see `SCHEMA_HARVEST_ENV` in core), the
|
|
24
|
+
* scaffolded module's own `export const env = load(schema)` must not stop the
|
|
25
|
+
* module from evaluating — an empty tree would throw here and take the `schema`
|
|
26
|
+
* export down with it, which is exactly the state `penv fill` exists to fix. In
|
|
27
|
+
* that window `load` returns a lazy stand-in that performs the real load — and
|
|
28
|
+
* raises the same parameter-named error — on first property access. Application
|
|
29
|
+
* runtime never sets the flag, so ordinary loads stay eager and fail-fast.
|
|
21
30
|
*/
|
|
22
31
|
declare function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T>;
|
|
23
32
|
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "@penvhq/core";
|
|
17
17
|
|
|
18
18
|
// src/load.ts
|
|
19
|
-
import { accessPath, ValidationError } from "@penvhq/core";
|
|
19
|
+
import { accessPath, schemaHarvestActive, ValidationError } from "@penvhq/core";
|
|
20
20
|
function place(root, path, value) {
|
|
21
21
|
const leaf = path[path.length - 1];
|
|
22
22
|
if (leaf === void 0) {
|
|
@@ -36,6 +36,12 @@ function place(root, path, value) {
|
|
|
36
36
|
node[leaf] = value;
|
|
37
37
|
}
|
|
38
38
|
function load(schema, options) {
|
|
39
|
+
if (schemaHarvestActive()) {
|
|
40
|
+
return deferLoad(schema, options);
|
|
41
|
+
}
|
|
42
|
+
return loadEagerly(schema, options);
|
|
43
|
+
}
|
|
44
|
+
function loadEagerly(schema, options) {
|
|
39
45
|
const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);
|
|
40
46
|
const object = {};
|
|
41
47
|
for (const { ref, value } of values) {
|
|
@@ -53,6 +59,35 @@ function load(schema, options) {
|
|
|
53
59
|
}
|
|
54
60
|
return result.data;
|
|
55
61
|
}
|
|
62
|
+
function deferLoad(schema, options) {
|
|
63
|
+
let materialized = false;
|
|
64
|
+
let value;
|
|
65
|
+
const materialize = () => {
|
|
66
|
+
if (!materialized) {
|
|
67
|
+
value = loadEagerly(schema, options);
|
|
68
|
+
materialized = true;
|
|
69
|
+
}
|
|
70
|
+
return Object(value);
|
|
71
|
+
};
|
|
72
|
+
return new Proxy({}, {
|
|
73
|
+
get(_target, property) {
|
|
74
|
+
if (schemaHarvestActive() && (typeof property === "symbol" || property === "then")) {
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
return Reflect.get(materialize(), property);
|
|
78
|
+
},
|
|
79
|
+
has(_target, property) {
|
|
80
|
+
return Reflect.has(materialize(), property);
|
|
81
|
+
},
|
|
82
|
+
ownKeys() {
|
|
83
|
+
return Reflect.ownKeys(materialize());
|
|
84
|
+
},
|
|
85
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
86
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(materialize(), property);
|
|
87
|
+
return descriptor === void 0 ? void 0 : { ...descriptor, configurable: true };
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
56
91
|
export {
|
|
57
92
|
ConfigError,
|
|
58
93
|
FilenameGrammarError,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/load.ts"],"sourcesContent":["/**\n * The public surface of `@penvhq/runtime` — what `penv` re-exports.\n *\n * `defineConfig` is re-exported from `@penvhq/core` because the docs show\n * `penv.config.ts` importing it from `penv`: one import specifier for the whole\n * tool, whatever package a symbol happens to live in.\n */\n\nexport {\n ConfigError,\n defineConfig,\n FilenameGrammarError,\n MissingParameterError,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n UnknownEnvironmentError,\n ValidationError,\n} from \"@penvhq/core\";\nexport type { LoadOptions } from \"./load.js\";\nexport { load } from \"./load.js\";\n","/**\n * The runtime loader. `load` is generic and returns `z.infer<T>` — the type the\n * caller's own schema describes, never a widened one. The inferred type is only\n * true because the same schema validates the values before they are returned,\n * so the type you code against and the value you receive cannot diverge.\n */\n\nimport { accessPath, ValidationError } from \"@penvhq/core\";\nimport type { z } from \"zod\";\nimport { resolveSync } from \"./resolve.js\";\n\nexport interface LoadOptions {\n /** Where to start looking for `penv.config.ts`. Defaults to `process.cwd()`. */\n readonly cwd?: string;\n /** Overrides `PENV_ENV` / `NODE_ENV`. Must be a declared environment. */\n readonly environment?: string;\n}\n\n/**\n * Places a value at its access path, creating namespaces on the way.\n * Values are placed exactly as the provider holds them: coercion is the\n * schema's job, so a value file's contents stay a string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\n/**\n * Loads, validates, and returns configuration for the current environment.\n * Eager and synchronous: invalid configuration fails at startup with a\n * parameter-named error rather than later at first use.\n */\nexport function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);\n\n const object: Record<string, unknown> = {};\n for (const { ref, value } of values) {\n place(object, accessPath(ref), value);\n }\n\n const result = schema.safeParse(object);\n if (!result.success) {\n throw new ValidationError(\n environment,\n result.error.issues.map((issue) => ({\n parameter: issue.path.join(\".\"),\n message: issue.message,\n })),\n );\n }\n return result.data;\n}\n"],"mappings":";;;;;AAQA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAAA;AAAA,OACK;;;ACXP,SAAS,YAAY,uBAAuB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/load.ts"],"sourcesContent":["/**\n * The public surface of `@penvhq/runtime` — what `penv` re-exports.\n *\n * `defineConfig` is re-exported from `@penvhq/core` because the docs show\n * `penv.config.ts` importing it from `penv`: one import specifier for the whole\n * tool, whatever package a symbol happens to live in.\n */\n\nexport {\n ConfigError,\n defineConfig,\n FilenameGrammarError,\n MissingParameterError,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n UnknownEnvironmentError,\n ValidationError,\n} from \"@penvhq/core\";\nexport type { LoadOptions } from \"./load.js\";\nexport { load } from \"./load.js\";\n","/**\n * The runtime loader. `load` is generic and returns `z.infer<T>` — the type the\n * caller's own schema describes, never a widened one. The inferred type is only\n * true because the same schema validates the values before they are returned,\n * so the type you code against and the value you receive cannot diverge.\n */\n\nimport { accessPath, schemaHarvestActive, ValidationError } from \"@penvhq/core\";\nimport type { z } from \"zod\";\nimport { resolveSync } from \"./resolve.js\";\n\nexport interface LoadOptions {\n /** Where to start looking for `penv.config.ts`. Defaults to `process.cwd()`. */\n readonly cwd?: string;\n /** Overrides `PENV_ENV` / `NODE_ENV`. Must be a declared environment. */\n readonly environment?: string;\n}\n\n/**\n * Places a value at its access path, creating namespaces on the way.\n * Values are placed exactly as the provider holds them: coercion is the\n * schema's job, so a value file's contents stay a string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\n/**\n * Loads, validates, and returns configuration for the current environment.\n * Eager and synchronous: invalid configuration fails at startup with a\n * parameter-named error rather than later at first use.\n *\n * One deliberate exception to the eagerness: while the CLI is harvesting the\n * `schema` export of `.penv/env.ts` (see `SCHEMA_HARVEST_ENV` in core), the\n * scaffolded module's own `export const env = load(schema)` must not stop the\n * module from evaluating — an empty tree would throw here and take the `schema`\n * export down with it, which is exactly the state `penv fill` exists to fix. In\n * that window `load` returns a lazy stand-in that performs the real load — and\n * raises the same parameter-named error — on first property access. Application\n * runtime never sets the flag, so ordinary loads stay eager and fail-fast.\n */\nexport function load<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n if (schemaHarvestActive()) {\n return deferLoad(schema, options);\n }\n return loadEagerly(schema, options);\n}\n\nfunction loadEagerly<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n const { environment, values } = resolveSync(options?.cwd ?? process.cwd(), options?.environment);\n\n const object: Record<string, unknown> = {};\n for (const { ref, value } of values) {\n place(object, accessPath(ref), value);\n }\n\n const result = schema.safeParse(object);\n if (!result.success) {\n throw new ValidationError(\n environment,\n result.error.issues.map((issue) => ({\n parameter: issue.path.join(\".\"),\n message: issue.message,\n })),\n );\n }\n return result.data;\n}\n\n/**\n * `load`'s harvest-time stand-in: nothing is resolved or validated until a\n * property is actually read. The schema module's top level only *binds*\n * `export const env`, so under harvest the binding succeeds, the CLI reads the\n * `schema` export, and the deferred error — if the tree still cannot satisfy the\n * schema — surfaces on first real use with the same `ValidationError` the eager\n * path throws.\n */\nfunction deferLoad<T extends z.ZodType>(schema: T, options?: LoadOptions): z.infer<T> {\n let materialized = false;\n let value: unknown;\n const materialize = (): object => {\n if (!materialized) {\n value = loadEagerly(schema, options);\n materialized = true;\n }\n // `Object(...)` keeps the traps total even for a schema whose root is not an\n // object — property reads then forward to the boxed primitive.\n return Object(value);\n };\n\n return new Proxy({} as Record<PropertyKey, unknown>, {\n get(_target, property) {\n // Module plumbing probes exported values while the harvest import is still\n // in flight — `then` (module namespaces are awaited by some loaders) and\n // well-known symbols (inspection). Those probes must not force the load;\n // real reads, which arrive after the harvest window closes, must.\n if (schemaHarvestActive() && (typeof property === \"symbol\" || property === \"then\")) {\n return undefined;\n }\n return Reflect.get(materialize(), property);\n },\n has(_target, property) {\n return Reflect.has(materialize(), property);\n },\n ownKeys() {\n return Reflect.ownKeys(materialize());\n },\n getOwnPropertyDescriptor(_target, property) {\n const descriptor = Reflect.getOwnPropertyDescriptor(materialize(), property);\n // Configurable, so the descriptor stays compatible with the empty proxy\n // target — the invariant check would throw for a frozen original otherwise.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true };\n },\n }) as z.infer<T>;\n}\n"],"mappings":";;;;;AAQA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAAA;AAAA,OACK;;;ACXP,SAAS,YAAY,qBAAqB,uBAAuB;AAgBjE,SAAS,MAAM,MAA+B,MAAyB,OAAqB;AAC1F,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,MAAI,SAAS,QAAW;AACtB;AAAA,EACF;AAEA,MAAI,OAAO;AACX,aAAW,OAAO,KAAK,MAAM,GAAG,EAAE,GAAG;AACnC,UAAM,WAAW,KAAK,GAAG;AACzB,QAAI,OAAO,aAAa,YAAY,aAAa,MAAM;AACrD,aAAO;AACP;AAAA,IACF;AACA,UAAM,QAAiC,CAAC;AACxC,SAAK,GAAG,IAAI;AACZ,WAAO;AAAA,EACT;AACA,OAAK,IAAI,IAAI;AACf;AAgBO,SAAS,KAA0B,QAAW,SAAmC;AACtF,MAAI,oBAAoB,GAAG;AACzB,WAAO,UAAU,QAAQ,OAAO;AAAA,EAClC;AACA,SAAO,YAAY,QAAQ,OAAO;AACpC;AAEA,SAAS,YAAiC,QAAW,SAAmC;AACtF,QAAM,EAAE,aAAa,OAAO,IAAI,YAAY,SAAS,OAAO,QAAQ,IAAI,GAAG,SAAS,WAAW;AAE/F,QAAM,SAAkC,CAAC;AACzC,aAAW,EAAE,KAAK,MAAM,KAAK,QAAQ;AACnC,UAAM,QAAQ,WAAW,GAAG,GAAG,KAAK;AAAA,EACtC;AAEA,QAAM,SAAS,OAAO,UAAU,MAAM;AACtC,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,QAClC,WAAW,MAAM,KAAK,KAAK,GAAG;AAAA,QAC9B,SAAS,MAAM;AAAA,MACjB,EAAE;AAAA,IACJ;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAUA,SAAS,UAA+B,QAAW,SAAmC;AACpF,MAAI,eAAe;AACnB,MAAI;AACJ,QAAM,cAAc,MAAc;AAChC,QAAI,CAAC,cAAc;AACjB,cAAQ,YAAY,QAAQ,OAAO;AACnC,qBAAe;AAAA,IACjB;AAGA,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,SAAO,IAAI,MAAM,CAAC,GAAmC;AAAA,IACnD,IAAI,SAAS,UAAU;AAKrB,UAAI,oBAAoB,MAAM,OAAO,aAAa,YAAY,aAAa,SAAS;AAClF,eAAO;AAAA,MACT;AACA,aAAO,QAAQ,IAAI,YAAY,GAAG,QAAQ;AAAA,IAC5C;AAAA,IACA,IAAI,SAAS,UAAU;AACrB,aAAO,QAAQ,IAAI,YAAY,GAAG,QAAQ;AAAA,IAC5C;AAAA,IACA,UAAU;AACR,aAAO,QAAQ,QAAQ,YAAY,CAAC;AAAA,IACtC;AAAA,IACA,yBAAyB,SAAS,UAAU;AAC1C,YAAM,aAAa,QAAQ,yBAAyB,YAAY,GAAG,QAAQ;AAG3E,aAAO,eAAe,SAAY,SAAY,EAAE,GAAG,YAAY,cAAc,KAAK;AAAA,IACpF;AAAA,EACF,CAAC;AACH;","names":["ValidationError"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penvhq/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "penv's load() and the typed env surface. Ships into user apps — keep it light.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@penvhq/core": "0.
|
|
27
|
-
"@penvhq/provider-filesystem": "0.
|
|
26
|
+
"@penvhq/core": "0.4.0",
|
|
27
|
+
"@penvhq/provider-filesystem": "0.4.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"zod": "^4.4.3"
|