@geekmidas/envkit 10.0.0-alpha.12 → 10.0.0-alpha.14
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/{EnvironmentBuilder-CoBQ9Xp2.d.mts → EnvironmentBuilder-DTZ8o3se.d.cts} +5 -5
- package/dist/EnvironmentBuilder-DTZ8o3se.d.cts.map +1 -0
- package/dist/{EnvironmentBuilder-DeIle4QN.d.cts → EnvironmentBuilder-DTZ8o3se.d.mts} +5 -5
- package/dist/EnvironmentBuilder-DTZ8o3se.d.mts.map +1 -0
- package/dist/{EnvironmentBuilder-C-2fViCT.mjs → EnvironmentBuilder-Rxq657gm.mjs} +4 -5
- package/dist/EnvironmentBuilder-Rxq657gm.mjs.map +1 -0
- package/dist/{EnvironmentBuilder-15SdFJdK.cjs → EnvironmentBuilder-wJH3EBbJ.cjs} +16 -16
- package/dist/EnvironmentBuilder-wJH3EBbJ.cjs.map +1 -0
- package/dist/{EnvironmentParser-DoooZm8n.d.cts → EnvironmentParser-BmJLlm5_.d.cts} +3 -15
- package/dist/EnvironmentParser-BmJLlm5_.d.cts.map +1 -0
- package/dist/{EnvironmentParser-BY1oCUsc.d.mts → EnvironmentParser-BmJLlm5_.d.mts} +3 -15
- package/dist/EnvironmentParser-BmJLlm5_.d.mts.map +1 -0
- package/dist/{EnvironmentParser-Bzg5yXG2.cjs → EnvironmentParser-CmhDxs77.cjs} +34 -34
- package/dist/EnvironmentParser-CmhDxs77.cjs.map +1 -0
- package/dist/{EnvironmentParser-taAKfzT7.mjs → EnvironmentParser-X6Z-jryw.mjs} +10 -12
- package/dist/EnvironmentParser-X6Z-jryw.mjs.map +1 -0
- package/dist/SnifferEnvironmentParser.cjs +5 -7
- package/dist/SnifferEnvironmentParser.cjs.map +1 -1
- package/dist/SnifferEnvironmentParser.d.cts +5 -9
- package/dist/SnifferEnvironmentParser.d.cts.map +1 -1
- package/dist/SnifferEnvironmentParser.d.mts +5 -9
- package/dist/SnifferEnvironmentParser.d.mts.map +1 -1
- package/dist/SnifferEnvironmentParser.mjs +3 -5
- package/dist/SnifferEnvironmentParser.mjs.map +1 -1
- package/dist/credentials.cjs +9 -11
- package/dist/credentials.cjs.map +1 -1
- package/dist/credentials.d.cts +3 -3
- package/dist/credentials.d.cts.map +1 -1
- package/dist/credentials.d.mts +3 -3
- package/dist/credentials.d.mts.map +1 -1
- package/dist/credentials.mjs +4 -8
- package/dist/credentials.mjs.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +5 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +5 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -4
- package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-VH7oDXx4.cjs} +8 -10
- package/dist/sst.cjs +43 -51
- package/dist/sst.cjs.map +1 -1
- package/dist/sst.d.cts +19 -24
- package/dist/sst.d.cts.map +1 -1
- package/dist/sst.d.mts +19 -24
- package/dist/sst.d.mts.map +1 -1
- package/dist/sst.mjs +42 -51
- package/dist/sst.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/EnvironmentBuilder-15SdFJdK.cjs.map +0 -1
- package/dist/EnvironmentBuilder-C-2fViCT.mjs.map +0 -1
- package/dist/EnvironmentBuilder-CoBQ9Xp2.d.mts.map +0 -1
- package/dist/EnvironmentBuilder-DeIle4QN.d.cts.map +0 -1
- package/dist/EnvironmentParser-BY1oCUsc.d.mts.map +0 -1
- package/dist/EnvironmentParser-Bzg5yXG2.cjs.map +0 -1
- package/dist/EnvironmentParser-DoooZm8n.d.cts.map +0 -1
- package/dist/EnvironmentParser-taAKfzT7.mjs.map +0 -1
package/dist/sst.d.mts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { a as EnvironmentResolver, i as EnvironmentBuilderOptions, n as EnvValue, o as InputValue, s as Resolvers, t as EnvRecord, u as environmentCase } from "./EnvironmentBuilder-DTZ8o3se.mjs";
|
|
3
2
|
//#region src/SstEnvironmentBuilder.d.ts
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Enumeration of supported SST (Serverless Stack Toolkit) resource types.
|
|
7
5
|
* Used to identify and process different AWS and SST resources.
|
|
8
6
|
*/
|
|
9
|
-
declare enum ResourceType {
|
|
7
|
+
export declare enum ResourceType {
|
|
10
8
|
ApiGatewayV2 = "sst.aws.ApiGatewayV2",
|
|
11
9
|
Postgres = "sst.aws.Postgres",
|
|
12
10
|
Function = "sst.aws.Function",
|
|
@@ -26,7 +24,7 @@ declare enum ResourceType {
|
|
|
26
24
|
FileServer = "sst:aws:Router",
|
|
27
25
|
StaticSite = "sst:aws:StaticSite",
|
|
28
26
|
Email = "gkm:aws:Email",
|
|
29
|
-
Cache = "gkm:aws:Cache"
|
|
27
|
+
Cache = "gkm:aws:Cache"
|
|
30
28
|
}
|
|
31
29
|
/**
|
|
32
30
|
* AWS API Gateway V2 resource type.
|
|
@@ -121,7 +119,7 @@ type ResourceProcessor<K> = (name: string, value: K) => EnvRecord;
|
|
|
121
119
|
/**
|
|
122
120
|
* Pre-configured resolvers for all SST resource types.
|
|
123
121
|
*/
|
|
124
|
-
declare const sstResolvers: Resolvers;
|
|
122
|
+
export declare const sstResolvers: Resolvers;
|
|
125
123
|
/**
|
|
126
124
|
* All known SST resource type strings.
|
|
127
125
|
*/
|
|
@@ -141,7 +139,7 @@ type OmitType<T> = T extends {
|
|
|
141
139
|
/**
|
|
142
140
|
* Extracts all unique `type` values from a record (excluding plain strings).
|
|
143
141
|
*/
|
|
144
|
-
type AllTypeValues<TRecord extends Record<string, InputValue>> = { [K in keyof TRecord]: ExtractType<TRecord[K]
|
|
142
|
+
type AllTypeValues<TRecord extends Record<string, InputValue>> = { [K in keyof TRecord]: ExtractType<TRecord[K]>; }[keyof TRecord];
|
|
145
143
|
/**
|
|
146
144
|
* Extracts only the custom (non-SST) type values from a record.
|
|
147
145
|
*/
|
|
@@ -151,11 +149,11 @@ type CustomTypeValues<TRecord extends Record<string, InputValue>> = Exclude<AllT
|
|
|
151
149
|
*/
|
|
152
150
|
type ValueForType<TRecord extends Record<string, InputValue>, TType extends string> = { [K in keyof TRecord]: TRecord[K] extends {
|
|
153
151
|
type: TType;
|
|
154
|
-
} ? OmitType<TRecord[K]> : never }[keyof TRecord];
|
|
152
|
+
} ? OmitType<TRecord[K]> : never; }[keyof TRecord];
|
|
155
153
|
/**
|
|
156
154
|
* Generates typed resolvers for custom (non-SST) types in the input record.
|
|
157
155
|
*/
|
|
158
|
-
type CustomResolvers<TRecord extends Record<string, InputValue>> = CustomTypeValues<TRecord> extends never ? Resolvers | undefined : { [TType in CustomTypeValues<TRecord>]: EnvironmentResolver<ValueForType<TRecord, TType
|
|
156
|
+
type CustomResolvers<TRecord extends Record<string, InputValue>> = CustomTypeValues<TRecord> extends never ? Resolvers | undefined : { [TType in CustomTypeValues<TRecord>]: EnvironmentResolver<ValueForType<TRecord, TType>>; };
|
|
159
157
|
/**
|
|
160
158
|
* SST-specific environment builder with built-in resolvers for all known
|
|
161
159
|
* SST resource types.
|
|
@@ -185,7 +183,7 @@ type CustomResolvers<TRecord extends Record<string, InputValue>> = CustomTypeVal
|
|
|
185
183
|
* ).build();
|
|
186
184
|
* ```
|
|
187
185
|
*/
|
|
188
|
-
declare class SstEnvironmentBuilder<TRecord extends Record<string, SstResource | InputValue | string>> {
|
|
186
|
+
export declare class SstEnvironmentBuilder<TRecord extends Record<string, SstResource | InputValue | string>> {
|
|
189
187
|
private readonly builder;
|
|
190
188
|
/**
|
|
191
189
|
* Create a new SST environment builder.
|
|
@@ -209,21 +207,21 @@ declare class SstEnvironmentBuilder<TRecord extends Record<string, SstResource |
|
|
|
209
207
|
* assumed — opt in via `platform: 'aws'` or by spreading {@link AWS_RUNTIME_ENV_VARS}
|
|
210
208
|
* into `whitelist`.
|
|
211
209
|
*/
|
|
212
|
-
declare const AWS_RUNTIME_ENV_VARS: readonly ["AWS_REGION", "AWS_DEFAULT_REGION", "AWS_ENDPOINT_URL", "AWS_ENDPOINT", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_LAMBDA_FUNCTION_NAME", "AWS_LAMBDA_FUNCTION_VERSION"];
|
|
210
|
+
export declare const AWS_RUNTIME_ENV_VARS: readonly ["AWS_REGION", "AWS_DEFAULT_REGION", "AWS_ENDPOINT_URL", "AWS_ENDPOINT", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_LAMBDA_FUNCTION_NAME", "AWS_LAMBDA_FUNCTION_VERSION"];
|
|
213
211
|
/**
|
|
214
212
|
* Variables GCP injects into Cloud Functions / Cloud Run.
|
|
215
213
|
*/
|
|
216
|
-
declare const GCP_RUNTIME_ENV_VARS: readonly ["GOOGLE_CLOUD_PROJECT", "GCP_PROJECT", "FUNCTION_TARGET", "FUNCTION_SIGNATURE_TYPE", "K_SERVICE", "K_REVISION", "K_CONFIGURATION", "PORT"];
|
|
214
|
+
export declare const GCP_RUNTIME_ENV_VARS: readonly ["GOOGLE_CLOUD_PROJECT", "GCP_PROJECT", "FUNCTION_TARGET", "FUNCTION_SIGNATURE_TYPE", "K_SERVICE", "K_REVISION", "K_CONFIGURATION", "PORT"];
|
|
217
215
|
/**
|
|
218
216
|
* Variables Cloudflare exposes to Workers. Workers inject almost nothing into
|
|
219
217
|
* the global env, so this is intentionally minimal.
|
|
220
218
|
*/
|
|
221
|
-
declare const CLOUDFLARE_RUNTIME_ENV_VARS: readonly ["CF_PAGES", "CF_PAGES_URL"];
|
|
219
|
+
export declare const CLOUDFLARE_RUNTIME_ENV_VARS: readonly ["CF_PAGES", "CF_PAGES_URL"];
|
|
222
220
|
/**
|
|
223
221
|
* Registry of platform → always-valid runtime variables. Export, don't assume:
|
|
224
222
|
* a caller states the platform it deploys to and the matching set is trusted.
|
|
225
223
|
*/
|
|
226
|
-
declare const PLATFORM_ENV_VARS: {
|
|
224
|
+
export declare const PLATFORM_ENV_VARS: {
|
|
227
225
|
readonly aws: readonly ["AWS_REGION", "AWS_DEFAULT_REGION", "AWS_ENDPOINT_URL", "AWS_ENDPOINT", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_LAMBDA_FUNCTION_NAME", "AWS_LAMBDA_FUNCTION_VERSION"];
|
|
228
226
|
readonly gcp: readonly ["GOOGLE_CLOUD_PROJECT", "GCP_PROJECT", "FUNCTION_TARGET", "FUNCTION_SIGNATURE_TYPE", "K_SERVICE", "K_REVISION", "K_CONFIGURATION", "PORT"];
|
|
229
227
|
readonly cloudflare: readonly ["CF_PAGES", "CF_PAGES_URL"];
|
|
@@ -233,7 +231,7 @@ type Platform = keyof typeof PLATFORM_ENV_VARS;
|
|
|
233
231
|
* The always-valid runtime variables for a platform. The "whitelist construct":
|
|
234
232
|
* resolve a platform to its set, to spread into `whitelist` or compare against.
|
|
235
233
|
*/
|
|
236
|
-
declare function platformEnvVars(platform: Platform): readonly string[];
|
|
234
|
+
export declare function platformEnvVars(platform: Platform): readonly string[];
|
|
237
235
|
/**
|
|
238
236
|
* Input shape for the validator: the same record `SstEnvironmentBuilder`
|
|
239
237
|
* accepts — keyed by resource name, valued by an SST resource (or a plain
|
|
@@ -271,7 +269,7 @@ interface EnvValidatorOptions {
|
|
|
271
269
|
* provide. Carries the structured `missing`/`available`/`suggestions` so callers
|
|
272
270
|
* can inspect the failure programmatically, not just read the message.
|
|
273
271
|
*/
|
|
274
|
-
declare class EnvValidationError extends Error {
|
|
272
|
+
export declare class EnvValidationError extends Error {
|
|
275
273
|
readonly isEnvValidationError = true;
|
|
276
274
|
readonly missing: string[];
|
|
277
275
|
readonly available: string[];
|
|
@@ -301,7 +299,7 @@ declare class EnvValidationError extends Error {
|
|
|
301
299
|
* resolveEnvKeys({ db: { type: ResourceType.Postgres } });
|
|
302
300
|
* // ['DB_NAME', 'DB_HOST', 'DB_PASSWORD', 'DB_PORT', 'DB_USERNAME', 'DB_URL']
|
|
303
301
|
*/
|
|
304
|
-
declare function resolveEnvKeys(record: LinkRecord): string[];
|
|
302
|
+
export declare function resolveEnvKeys(record: LinkRecord): string[];
|
|
305
303
|
/**
|
|
306
304
|
* Validates that the environment variables a deployable unit requires are
|
|
307
305
|
* actually provided by its linked resources — at infra time, before deploy.
|
|
@@ -320,7 +318,7 @@ declare function resolveEnvKeys(record: LinkRecord): string[];
|
|
|
320
318
|
* validator.assert(['DB_HOST', 'AWS_REGION', 'APP_NAME', 'SENTRY_DSN?']); // ok
|
|
321
319
|
* validator.assert(['DATABASE_URL']); // throws EnvValidationError (did you mean DB_URL?)
|
|
322
320
|
*/
|
|
323
|
-
declare class EnvValidator {
|
|
321
|
+
export declare class EnvValidator {
|
|
324
322
|
/** Every variable available — link-derived, platform, and extra whitelist. */
|
|
325
323
|
readonly availableVars: string[];
|
|
326
324
|
/** Just the variables the links provide (used for error context). */
|
|
@@ -355,7 +353,6 @@ declare class EnvValidator {
|
|
|
355
353
|
*/
|
|
356
354
|
has(envVar: string): boolean;
|
|
357
355
|
}
|
|
358
|
-
//# sourceMappingURL=SstEnvValidator.d.ts.map
|
|
359
356
|
//#endregion
|
|
360
357
|
//#region src/sst.d.ts
|
|
361
358
|
/**
|
|
@@ -374,13 +371,11 @@ declare class EnvValidator {
|
|
|
374
371
|
* // New usage:
|
|
375
372
|
* new SstEnvironmentBuilder({ database: postgresResource }).build()
|
|
376
373
|
*/
|
|
377
|
-
declare function normalizeResourceEnv(record: Record<string, SstResource | string>): Record<string, string | number | boolean | Record<string, unknown>>;
|
|
374
|
+
export declare function normalizeResourceEnv(record: Record<string, SstResource | string>): Record<string, string | number | boolean | Record<string, unknown>>;
|
|
378
375
|
/**
|
|
379
376
|
* @deprecated Use `SstResource` instead.
|
|
380
377
|
*/
|
|
381
|
-
type Resource = SstResource;
|
|
382
|
-
//# sourceMappingURL=sst.d.ts.map
|
|
383
|
-
|
|
378
|
+
export type Resource = SstResource;
|
|
384
379
|
//#endregion
|
|
385
|
-
export {
|
|
380
|
+
export { type ApiGatewayV2, type Bucket, type Dynamo, type EnvRecord, type EnvValidatorOptions, type EnvValue, type EnvironmentBuilderOptions, type Function, type LinkRecord, type Platform, type Postgres, type Queue, type ResourceProcessor, type Secret, type SnsTopic, type SstResource, type ValidationResult, type Vpc, environmentCase };
|
|
386
381
|
//# sourceMappingURL=sst.d.mts.map
|
package/dist/sst.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sst.d.mts","names":[],"sources":["../src/SstEnvironmentBuilder.ts","../src/SstEnvValidator.ts","../src/sst.ts"],"
|
|
1
|
+
{"version":3,"file":"sst.d.mts","names":[],"sources":["../src/SstEnvironmentBuilder.ts","../src/SstEnvValidator.ts","../src/sst.ts"],"mappings":";;;;;;oBAaY;EAEX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAKA;EACA;EAGA;EACA;;;;;;KAOW;EACX,MAAM,aAAa,eAAe,aAAa;EAC/C;;;;;;KAOW;EACX,MAAM,aAAa,WAAW,aAAa;EAC3C;EACA;EACA;EACA;EACA;;;;;KAMW;EACX,MAAM,aAAa,WAAW,aAAa;EAC3C;;;;;KAMW;EACX,MAAM,aAAa,gBAAgB,aAAa;EAChD;;;;;;EAMA;EACA;;;;;KAMW;EACX,MAAM,aAAa;EACnB;;;;;KAMW;EACX,MAAM,aAAa,SAAS,aAAa;EACzC;;;;;KAMW;EACX,MAAM,aAAa;EACnB;;;;;KAMW;EACX,MAAM,aAAa,QAAQ,aAAa;EACxC;EACA;;;;;KAMW;EACX,MAAM,aAAa,SAAS,aAAa;EACzC;;;;;KAMW,cACT,eACA,WACA,WACA,SACA,MACA,SACA,WACA,QACA;;;;;;;;;KAkBS,kBAAkB,MAAM,cAAc,OAAO,MAAM;;;;qBAkDlD,cAAc;;;;KAyBtB,2BAA2B;;;;KAK3B,YAAY,KAAK;EAAY,YAAY;IAAqB;;;;KAK9D,SAAS,KAAK;EAAY;IAAiB,KAAK;;;;KAKhD,cAAc,gBAAgB,eAAe,kBAChD,WAAW,UAAU,YAAY,QAAQ,aACnC;;;;KAKH,iBAAiB,gBAAgB,eAAe,eAAe,QACnE,cAAc,UACd;;;;KAMI,aACJ,gBAAgB,eAAe,aAC/B,2BAEC,WAAW,UAAU,QAAQ;EAAa,MAAM;IAC9C,SAAS,QAAQ,qBAEb;;;;KAKH,gBAAgB,gBAAgB,eAAe,eACnD,iBAAiB,yBACd,2BAEC,SAAS,iBAAiB,WAAW,oBACrC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAiCd,sBACZ,gBAAgB,eAAe,cAAc;mBAE5B;;;;;;;;EAahB,YAAA,QAAQ,SACR,sBAAsB,gBAAgB,UACtC,UAAU;;;;;;EAmBX,SAAS;;;;;;;;;qBCzVG;;;;qBAeA;;;;;qBAeA;;;;;qBASA;;;;;KAMD,wBAAwB;;;;;wBAMpB,gBAAgB,UAAU;;;;;;KAe9B,aAAa,eAAe,cAAc;UAErC;EAChB;;EAEA;;EAEA;;EAEA,aAAa;;UAGG;;;;;EAKhB,WAAW;;;;;EAKX;;;;;EAKA;;;;;;;qBAsEY,2BAA2B;WAC9B;WACA;WACA;WACA,aAAa;WACb;EAEG,YAAA;IACX;IACA;IACA;IACA,aAAa;IACb;;iBAgBc;;;;;;;;;;;;;;;;;wBA+CA,eAAe,QAAQ;;;;;;;;;;;;;;;;;;;qBA0B1B;;WAEH;;WAEA;WACA;mBACQ;;mBAEA;EAEL,YAAA,OAAO,YAAY,UAAS;;;;;;EAuBxC,uBAAuB;;;;;;EAgBvB,SAAS,sCAAsC;;;;;;;EA0B/C,OAAO;;;;;EAkBP,IAAI;;;;;;;;;;;;;;;;;;;;wBC5SW,qBACf,QAAQ,eAAe,wBACrB,2CAA2C;;;;YAQlC,WAAW"}
|
package/dist/sst.mjs
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { n as environmentCase, t as EnvironmentBuilder } from "./EnvironmentBuilder-Rxq657gm.mjs";
|
|
3
2
|
//#region src/SstEnvironmentBuilder.ts
|
|
4
3
|
/**
|
|
5
4
|
* Enumeration of supported SST (Serverless Stack Toolkit) resource types.
|
|
6
5
|
* Used to identify and process different AWS and SST resources.
|
|
7
6
|
*/
|
|
8
|
-
let ResourceType = /* @__PURE__ */ function(ResourceType
|
|
9
|
-
ResourceType
|
|
10
|
-
ResourceType
|
|
11
|
-
ResourceType
|
|
12
|
-
ResourceType
|
|
13
|
-
ResourceType
|
|
14
|
-
ResourceType
|
|
15
|
-
ResourceType
|
|
16
|
-
ResourceType
|
|
17
|
-
ResourceType
|
|
18
|
-
ResourceType
|
|
19
|
-
ResourceType
|
|
20
|
-
ResourceType
|
|
21
|
-
ResourceType
|
|
22
|
-
ResourceType
|
|
23
|
-
ResourceType
|
|
24
|
-
ResourceType
|
|
25
|
-
ResourceType
|
|
26
|
-
ResourceType
|
|
27
|
-
ResourceType
|
|
28
|
-
ResourceType
|
|
29
|
-
return ResourceType
|
|
7
|
+
let ResourceType = /* @__PURE__ */ function(ResourceType) {
|
|
8
|
+
ResourceType["ApiGatewayV2"] = "sst.aws.ApiGatewayV2";
|
|
9
|
+
ResourceType["Postgres"] = "sst.aws.Postgres";
|
|
10
|
+
ResourceType["Function"] = "sst.aws.Function";
|
|
11
|
+
ResourceType["ObjectStorage"] = "sst.aws.Bucket";
|
|
12
|
+
ResourceType["Vpc"] = "sst.aws.Vpc";
|
|
13
|
+
ResourceType["Secret"] = "sst.sst.Secret";
|
|
14
|
+
ResourceType["Dynamo"] = "sst.aws.Dynamo";
|
|
15
|
+
ResourceType["Queue"] = "sst.aws.Queue";
|
|
16
|
+
ResourceType["SSTSecret"] = "sst:sst:Secret";
|
|
17
|
+
ResourceType["SSTFunction"] = "sst:sst:Function";
|
|
18
|
+
ResourceType["SSTApiGatewayV2"] = "sst:aws:ApiGatewayV2";
|
|
19
|
+
ResourceType["SSTPostgres"] = "sst:aws:Postgres";
|
|
20
|
+
ResourceType["SSTObjectStorage"] = "sst:aws:Bucket";
|
|
21
|
+
ResourceType["SnsTopic"] = "sst:aws:SnsTopic";
|
|
22
|
+
ResourceType["SSTDynamo"] = "sst:aws:Dynamo";
|
|
23
|
+
ResourceType["SSTQueue"] = "sst:aws:Queue";
|
|
24
|
+
ResourceType["FileServer"] = "sst:aws:Router";
|
|
25
|
+
ResourceType["StaticSite"] = "sst:aws:StaticSite";
|
|
26
|
+
ResourceType["Email"] = "gkm:aws:Email";
|
|
27
|
+
ResourceType["Cache"] = "gkm:aws:Cache";
|
|
28
|
+
return ResourceType;
|
|
30
29
|
}({});
|
|
31
30
|
const secretResolver = (name, value) => ({ [name]: value.value });
|
|
32
31
|
const postgresResolver = (key, value) => ({
|
|
@@ -56,22 +55,22 @@ const noopResolver = () => ({});
|
|
|
56
55
|
* Pre-configured resolvers for all SST resource types.
|
|
57
56
|
*/
|
|
58
57
|
const sstResolvers = {
|
|
59
|
-
[
|
|
60
|
-
[
|
|
61
|
-
[
|
|
62
|
-
[
|
|
63
|
-
[
|
|
64
|
-
[
|
|
65
|
-
[
|
|
66
|
-
[
|
|
67
|
-
[
|
|
68
|
-
[
|
|
69
|
-
[
|
|
70
|
-
[
|
|
71
|
-
[
|
|
72
|
-
[
|
|
73
|
-
[
|
|
74
|
-
[
|
|
58
|
+
["sst.aws.ApiGatewayV2"]: noopResolver,
|
|
59
|
+
["sst.aws.Function"]: noopResolver,
|
|
60
|
+
["sst.aws.Vpc"]: noopResolver,
|
|
61
|
+
["sst.sst.Secret"]: secretResolver,
|
|
62
|
+
["sst.aws.Postgres"]: postgresResolver,
|
|
63
|
+
["sst.aws.Bucket"]: bucketResolver,
|
|
64
|
+
["sst.aws.Dynamo"]: dynamoResolver,
|
|
65
|
+
["sst.aws.Queue"]: queueResolver,
|
|
66
|
+
["sst:sst:Secret"]: secretResolver,
|
|
67
|
+
["sst:aws:Bucket"]: bucketResolver,
|
|
68
|
+
["sst:sst:Function"]: noopResolver,
|
|
69
|
+
["sst:aws:Postgres"]: postgresResolver,
|
|
70
|
+
["sst:aws:ApiGatewayV2"]: noopResolver,
|
|
71
|
+
["sst:aws:SnsTopic"]: topicResolver,
|
|
72
|
+
["sst:aws:Dynamo"]: dynamoResolver,
|
|
73
|
+
["sst:aws:Queue"]: queueResolver
|
|
75
74
|
};
|
|
76
75
|
/**
|
|
77
76
|
* SST-specific environment builder with built-in resolvers for all known
|
|
@@ -127,7 +126,6 @@ var SstEnvironmentBuilder = class {
|
|
|
127
126
|
return this.builder.build();
|
|
128
127
|
}
|
|
129
128
|
};
|
|
130
|
-
|
|
131
129
|
//#endregion
|
|
132
130
|
//#region src/SstEnvValidator.ts
|
|
133
131
|
/**
|
|
@@ -215,9 +213,7 @@ function similarity(a, b) {
|
|
|
215
213
|
const editSim = 1 - levenshtein(a, b) / Math.max(a.length, b.length, 1);
|
|
216
214
|
const ta = new Set(a.split("_").filter(Boolean));
|
|
217
215
|
const tb = new Set(b.split("_").filter(Boolean));
|
|
218
|
-
const
|
|
219
|
-
const union = new Set([...ta, ...tb]).size || 1;
|
|
220
|
-
const tokenSim = shared / union;
|
|
216
|
+
const tokenSim = [...ta].filter((t) => tb.has(t)).length / ((/* @__PURE__ */ new Set([...ta, ...tb])).size || 1);
|
|
221
217
|
return Math.max(editSim, tokenSim * 1.15);
|
|
222
218
|
}
|
|
223
219
|
/**
|
|
@@ -261,11 +257,7 @@ var EnvValidationError = class EnvValidationError extends Error {
|
|
|
261
257
|
});
|
|
262
258
|
let provided;
|
|
263
259
|
if (linkVars.length === 0) provided = "(no links provide environment variables)";
|
|
264
|
-
else {
|
|
265
|
-
const shown = linkVars.slice(0, MAX_LISTED_VARS).join(", ");
|
|
266
|
-
const extra = linkVars.length > MAX_LISTED_VARS ? ` ...(+${linkVars.length - MAX_LISTED_VARS})` : "";
|
|
267
|
-
provided = `Provided by links: ${shown}${extra}`;
|
|
268
|
-
}
|
|
260
|
+
else provided = `Provided by links: ${linkVars.slice(0, MAX_LISTED_VARS).join(", ")}${linkVars.length > MAX_LISTED_VARS ? ` ...(+${linkVars.length - MAX_LISTED_VARS})` : ""}`;
|
|
269
261
|
return `${who} is missing required env vars:\n${lines.join("\n")}\n\n${provided}`;
|
|
270
262
|
}
|
|
271
263
|
};
|
|
@@ -385,7 +377,6 @@ var EnvValidator = class {
|
|
|
385
377
|
return this.availableSet.has(envVar);
|
|
386
378
|
}
|
|
387
379
|
};
|
|
388
|
-
|
|
389
380
|
//#endregion
|
|
390
381
|
//#region src/sst.ts
|
|
391
382
|
/**
|
|
@@ -407,7 +398,7 @@ var EnvValidator = class {
|
|
|
407
398
|
function normalizeResourceEnv(record) {
|
|
408
399
|
return new SstEnvironmentBuilder(record).build();
|
|
409
400
|
}
|
|
410
|
-
|
|
411
401
|
//#endregion
|
|
412
402
|
export { AWS_RUNTIME_ENV_VARS, CLOUDFLARE_RUNTIME_ENV_VARS, EnvValidationError, EnvValidator, GCP_RUNTIME_ENV_VARS, PLATFORM_ENV_VARS, ResourceType, SstEnvironmentBuilder, environmentCase, normalizeResourceEnv, platformEnvVars, resolveEnvKeys, sstResolvers };
|
|
403
|
+
|
|
413
404
|
//# sourceMappingURL=sst.mjs.map
|
package/dist/sst.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sst.mjs","names":["name: string","value: SecretValue","key: string","value: PostgresValue","value: BucketValue","value: SnsTopicValue","value: QueueValue","value: DynamoValue","sstResolvers: Resolvers","record: TRecord","additionalResolvers?: CustomResolvers<TRecord>","options?: EnvironmentBuilderOptions","mergedResolvers: Resolvers","platform: Platform","a: string","b: string","curr: number[]","missing: string","available: readonly string[]","args: {\n\t\tmissing: string[];\n\t\tavailable: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}","args: {\n\t\tmissing: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}","provided: string","record: LinkRecord","typeOnly: Record<string, InputValue>","links: LinkRecord","options: EnvValidatorOptions","requestedEnvVars: readonly string[]","providers: string[]","suggestions: Record<string, string[]>","envVar: string","record: Record<string, SstResource | string>"],"sources":["../src/SstEnvironmentBuilder.ts","../src/SstEnvValidator.ts","../src/sst.ts"],"sourcesContent":["import {\n\tEnvironmentBuilder,\n\ttype EnvironmentBuilderOptions,\n\ttype EnvironmentResolver,\n\ttype EnvRecord,\n\ttype InputValue,\n\ttype Resolvers,\n} from './EnvironmentBuilder';\n\n/**\n * Enumeration of supported SST (Serverless Stack Toolkit) resource types.\n * Used to identify and process different AWS and SST resources.\n */\nexport enum ResourceType {\n\t// Legacy format (dot notation)\n\tApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n\tPostgres = 'sst.aws.Postgres',\n\tFunction = 'sst.aws.Function',\n\tObjectStorage = 'sst.aws.Bucket',\n\tVpc = 'sst.aws.Vpc',\n\tSecret = 'sst.sst.Secret',\n\tDynamo = 'sst.aws.Dynamo',\n\tQueue = 'sst.aws.Queue',\n\n\t// Modern format (colon notation)\n\tSSTSecret = 'sst:sst:Secret',\n\tSSTFunction = 'sst:sst:Function',\n\tSSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n\tSSTPostgres = 'sst:aws:Postgres',\n\tSSTObjectStorage = 'sst:aws:Bucket',\n\tSnsTopic = 'sst:aws:SnsTopic',\n\tSSTDynamo = 'sst:aws:Dynamo',\n\tSSTQueue = 'sst:aws:Queue',\n\t// A distribution, twice over: a file server and a static site are the same\n\t// infrastructure with different contents behind it, and they are separate\n\t// entries because what they provide is read under different ids, not\n\t// because SST builds them differently.\n\tFileServer = 'sst:aws:Router',\n\tStaticSite = 'sst:aws:StaticSite',\n\t// Neither is an SST component: mail is an IAM chain and a composed URL, and\n\t// a cache is whatever the selected backend turned out to be.\n\tEmail = 'gkm:aws:Email',\n\tCache = 'gkm:aws:Cache',\n}\n\n/**\n * AWS API Gateway V2 resource type.\n * Represents an HTTP/WebSocket API.\n */\nexport type ApiGatewayV2 = {\n\ttype: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n\turl: string;\n};\n\n/**\n * PostgreSQL database resource type.\n * Contains all connection details needed to connect to the database.\n */\nexport type Postgres = {\n\ttype: ResourceType.Postgres | ResourceType.SSTPostgres;\n\tdatabase: string;\n\thost: string;\n\tpassword: string;\n\tport: number;\n\tusername: string;\n};\n\n/**\n * AWS Lambda Function resource type.\n */\nexport type Function = {\n\ttype: ResourceType.Function | ResourceType.SSTFunction;\n\tname: string;\n};\n\n/**\n * AWS S3 Bucket resource type.\n */\nexport type Bucket = {\n\ttype: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;\n\tname: string;\n\t/**\n\t * Supplied by `@geekmidas/cloud`'s ObjectStorage, which widens SST's link to\n\t * carry them — a bucket may not be in the reader's region, and the URL is\n\t * composed where the resource's shape is known.\n\t */\n\tregion?: string;\n\turl?: string;\n};\n\n/**\n * AWS VPC (Virtual Private Cloud) resource type.\n */\nexport type Vpc = {\n\ttype: ResourceType.Vpc;\n\tbastion: string;\n};\n\n/**\n * Secret resource type for storing sensitive values.\n */\nexport type Secret = {\n\ttype: ResourceType.Secret | ResourceType.SSTSecret;\n\tvalue: string;\n};\n\n/**\n * AWS SNS Topic resource type.\n */\nexport type SnsTopic = {\n\ttype: ResourceType.SnsTopic;\n\tarn: string;\n};\n\n/**\n * AWS SQS Queue resource type.\n */\nexport type Queue = {\n\ttype: ResourceType.Queue | ResourceType.SSTQueue;\n\turl: string;\n\tarn: string;\n};\n\n/**\n * AWS DynamoDB Table resource type.\n */\nexport type Dynamo = {\n\ttype: ResourceType.Dynamo | ResourceType.SSTDynamo;\n\tname: string;\n};\n\n/**\n * Union type of all supported SST resource types.\n */\nexport type SstResource =\n\t| ApiGatewayV2\n\t| Postgres\n\t| Function\n\t| Bucket\n\t| Vpc\n\t| Secret\n\t| SnsTopic\n\t| Queue\n\t| Dynamo;\n\n// Value types without the `type` key (for resolver parameters)\ntype SecretValue = Omit<Secret, 'type'>;\ntype PostgresValue = Omit<Postgres, 'type'>;\ntype BucketValue = Omit<Bucket, 'type'>;\ntype SnsTopicValue = Omit<SnsTopic, 'type'>;\ntype QueueValue = Omit<Queue, 'type'>;\ntype DynamoValue = Omit<Dynamo, 'type'>;\n\n/**\n * Function type for processing a specific resource type into environment variables.\n *\n * @template K - The specific resource type (without `type` key)\n * @param name - The resource name\n * @param value - The resource value (without `type` key)\n * @returns Object mapping environment variable names to values\n */\nexport type ResourceProcessor<K> = (name: string, value: K) => EnvRecord;\n\n// SST Resource Resolvers (receive values without `type` key)\n\nconst secretResolver = (name: string, value: SecretValue) => ({\n\t[name]: value.value,\n});\n\nconst postgresResolver = (key: string, value: PostgresValue) => ({\n\t[`${key}Name`]: value.database,\n\t[`${key}Host`]: value.host,\n\t[`${key}Password`]: value.password,\n\t[`${key}Port`]: value.port,\n\t[`${key}Username`]: value.username,\n\t[`${key}Url`]: `postgresql://${encodeURIComponent(value.username)}:${encodeURIComponent(value.password)}@${value.host}:${value.port}/${value.database}`,\n});\n\nconst bucketResolver = (name: string, value: BucketValue) => ({\n\t[`${name}Name`]: value.name,\n\t// The single URL a construct reads. Composed by the component, which knows\n\t// its own shape; this only renames it into env case. Always emitted, even\n\t// when absent, so `resolveEnvKeys` can derive the key from the link's type\n\t// alone — a bucket linked without our component yields an empty one.\n\t[`${name}Url`]: value.url ?? '',\n});\n\nconst topicResolver = (name: string, value: SnsTopicValue) => ({\n\t[`${name}Arn`]: value.arn,\n\t// A publisher connection string for `@geekmidas/events` (SNS); region is\n\t// resolved from the ARN / AWS_REGION at runtime.\n\t[`${name}PublisherConnectionString`]: `sns://?topicArn=${encodeURIComponent(value.arn)}`,\n});\n\nconst queueResolver = (name: string, value: QueueValue) => ({\n\t[`${name}Url`]: value.url,\n\t[`${name}Arn`]: value.arn,\n\t// A publisher connection string for `@geekmidas/events` (SQS); region is\n\t// resolved from the URL / AWS_REGION at runtime.\n\t[`${name}PublisherConnectionString`]: `sqs://?queueUrl=${encodeURIComponent(value.url)}`,\n});\n\nconst dynamoResolver = (name: string, value: DynamoValue) => ({\n\t[`${name}Name`]: value.name,\n});\n\nconst noopResolver = () => ({});\n\n/**\n * Pre-configured resolvers for all SST resource types.\n */\nexport const sstResolvers: Resolvers = {\n\t// Legacy format\n\t[ResourceType.ApiGatewayV2]: noopResolver,\n\t[ResourceType.Function]: noopResolver,\n\t[ResourceType.Vpc]: noopResolver,\n\t[ResourceType.Secret]: secretResolver,\n\t[ResourceType.Postgres]: postgresResolver,\n\t[ResourceType.ObjectStorage]: bucketResolver,\n\t[ResourceType.Dynamo]: dynamoResolver,\n\t[ResourceType.Queue]: queueResolver,\n\n\t// Modern format\n\t[ResourceType.SSTSecret]: secretResolver,\n\t[ResourceType.SSTObjectStorage]: bucketResolver,\n\t[ResourceType.SSTFunction]: noopResolver,\n\t[ResourceType.SSTPostgres]: postgresResolver,\n\t[ResourceType.SSTApiGatewayV2]: noopResolver,\n\t[ResourceType.SnsTopic]: topicResolver,\n\t[ResourceType.SSTDynamo]: dynamoResolver,\n\t[ResourceType.SSTQueue]: queueResolver,\n};\n\n/**\n * All known SST resource type strings.\n */\ntype SstResourceTypeString = `${ResourceType}`;\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * Extracts only the custom (non-SST) type values from a record.\n */\ntype CustomTypeValues<TRecord extends Record<string, InputValue>> = Exclude<\n\tAllTypeValues<TRecord>,\n\tSstResourceTypeString\n>;\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers for custom (non-SST) types in the input record.\n */\ntype CustomResolvers<TRecord extends Record<string, InputValue>> =\n\tCustomTypeValues<TRecord> extends never\n\t\t? Resolvers | undefined\n\t\t: {\n\t\t\t\t[TType in CustomTypeValues<TRecord>]: EnvironmentResolver<\n\t\t\t\t\tValueForType<TRecord, TType>\n\t\t\t\t>;\n\t\t\t};\n\n/**\n * SST-specific environment builder with built-in resolvers for all known\n * SST resource types.\n *\n * Wraps the generic EnvironmentBuilder with pre-configured SST resolvers.\n *\n * @template TRecord - The input record type for type inference\n *\n * @example\n * ```typescript\n * const env = new SstEnvironmentBuilder({\n * database: { type: 'sst:aws:Postgres', host: '...', ... },\n * apiKey: { type: 'sst:sst:Secret', value: 'secret' },\n * appName: 'my-app',\n * }).build();\n *\n * // With custom resolvers (typed based on input)\n * const env = new SstEnvironmentBuilder(\n * {\n * database: postgresResource,\n * custom: { type: 'my-custom' as const, data: 'foo' },\n * },\n * {\n * // TypeScript requires 'my-custom' resolver with typed value\n * 'my-custom': (key, value) => ({ [`${key}Data`]: value.data }),\n * }\n * ).build();\n * ```\n */\nexport class SstEnvironmentBuilder<\n\tTRecord extends Record<string, SstResource | InputValue | string>,\n> {\n\tprivate readonly builder: EnvironmentBuilder<\n\t\tRecord<string, InputValue>,\n\t\tResolvers\n\t>;\n\n\t/**\n\t * Create a new SST environment builder.\n\t *\n\t * @param record - Object containing SST resources, custom resources, and/or string values\n\t * @param additionalResolvers - Optional custom resolvers (typed based on custom types in record)\n\t * @param options - Optional configuration options\n\t */\n\tconstructor(\n\t\trecord: TRecord,\n\t\tadditionalResolvers?: CustomResolvers<TRecord>,\n\t\toptions?: EnvironmentBuilderOptions,\n\t) {\n\t\t// Merge resolvers with custom ones taking precedence\n\t\tconst mergedResolvers: Resolvers = additionalResolvers\n\t\t\t? { ...sstResolvers, ...additionalResolvers }\n\t\t\t: sstResolvers;\n\n\t\tthis.builder = new EnvironmentBuilder(\n\t\t\trecord as Record<string, InputValue>,\n\t\t\tmergedResolvers,\n\t\t\toptions,\n\t\t);\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\treturn this.builder.build();\n\t}\n}\n\nexport type {\n\tEnvironmentBuilderOptions,\n\tEnvRecord,\n\tEnvValue,\n} from './EnvironmentBuilder';\n// Re-export useful types\nexport { environmentCase } from './EnvironmentBuilder';\n","import { EnvironmentBuilder, type InputValue } from './EnvironmentBuilder';\nimport { type SstResource, sstResolvers } from './SstEnvironmentBuilder';\n\n/**\n * Variables AWS Lambda injects into the runtime. Always valid on AWS, but never\n * assumed — opt in via `platform: 'aws'` or by spreading {@link AWS_RUNTIME_ENV_VARS}\n * into `whitelist`.\n */\nexport const AWS_RUNTIME_ENV_VARS = [\n\t'AWS_REGION',\n\t'AWS_DEFAULT_REGION',\n\t'AWS_ENDPOINT_URL',\n\t'AWS_ENDPOINT',\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_SESSION_TOKEN',\n\t'AWS_LAMBDA_FUNCTION_NAME',\n\t'AWS_LAMBDA_FUNCTION_VERSION',\n] as const;\n\n/**\n * Variables GCP injects into Cloud Functions / Cloud Run.\n */\nexport const GCP_RUNTIME_ENV_VARS = [\n\t'GOOGLE_CLOUD_PROJECT',\n\t'GCP_PROJECT',\n\t'FUNCTION_TARGET',\n\t'FUNCTION_SIGNATURE_TYPE',\n\t'K_SERVICE',\n\t'K_REVISION',\n\t'K_CONFIGURATION',\n\t'PORT',\n] as const;\n\n/**\n * Variables Cloudflare exposes to Workers. Workers inject almost nothing into\n * the global env, so this is intentionally minimal.\n */\nexport const CLOUDFLARE_RUNTIME_ENV_VARS = [\n\t'CF_PAGES',\n\t'CF_PAGES_URL',\n] as const;\n\n/**\n * Registry of platform → always-valid runtime variables. Export, don't assume:\n * a caller states the platform it deploys to and the matching set is trusted.\n */\nexport const PLATFORM_ENV_VARS = {\n\taws: AWS_RUNTIME_ENV_VARS,\n\tgcp: GCP_RUNTIME_ENV_VARS,\n\tcloudflare: CLOUDFLARE_RUNTIME_ENV_VARS,\n} as const;\n\nexport type Platform = keyof typeof PLATFORM_ENV_VARS;\n\n/**\n * The always-valid runtime variables for a platform. The \"whitelist construct\":\n * resolve a platform to its set, to spread into `whitelist` or compare against.\n */\nexport function platformEnvVars(platform: Platform): readonly string[] {\n\treturn PLATFORM_ENV_VARS[platform];\n}\n\n/** How many link-provided vars to list in an error before truncating. */\nconst MAX_LISTED_VARS = 8;\n\n/** Minimum similarity for a variable to be offered as a \"did you mean\". */\nconst SUGGESTION_THRESHOLD = 0.3;\n\n/**\n * Input shape for the validator: the same record `SstEnvironmentBuilder`\n * accepts — keyed by resource name, valued by an SST resource (or a plain\n * string for pass-through env vars).\n */\nexport type LinkRecord = Record<string, SstResource | InputValue | string>;\n\nexport interface ValidationResult {\n\tvalid: boolean;\n\t/** Requested variables that are not available (excluding optional `?` vars). */\n\tinvalidVars: string[];\n\t/** Every variable the links + whitelist make available. */\n\tavailableVars: string[];\n\t/** Nearest available matches for each invalid variable (best first). */\n\tsuggestions: Record<string, string[]>;\n}\n\nexport interface EnvValidatorOptions {\n\t/**\n\t * Platform whose runtime-injected variables are always valid. Omit to assume\n\t * none — the validator never bakes in a platform's variables.\n\t */\n\tplatform?: Platform;\n\t/**\n\t * Extra always-valid variables in addition to the platform set — typically\n\t * the keys of a function's explicit `environment`.\n\t */\n\twhitelist?: readonly string[];\n\t/**\n\t * Label for the deployable unit (e.g. a function name), used in error\n\t * messages so a failure points at exactly one unit.\n\t */\n\tcontext?: string;\n}\n\n/**\n * Levenshtein edit distance between two strings.\n */\nfunction levenshtein(a: string, b: string): number {\n\tconst m = a.length;\n\tconst n = b.length;\n\tif (m === 0) return n;\n\tif (n === 0) return m;\n\n\tlet prev = Array.from({ length: n + 1 }, (_, i) => i);\n\n\tfor (let i = 1; i <= m; i++) {\n\t\tconst curr: number[] = [i];\n\t\tfor (let j = 1; j <= n; j++) {\n\t\t\tconst cost = a[i - 1] === b[j - 1] ? 0 : 1;\n\t\t\tconst del = (prev[j] ?? 0) + 1;\n\t\t\tconst ins = (curr[j - 1] ?? 0) + 1;\n\t\t\tconst sub = (prev[j - 1] ?? 0) + cost;\n\t\t\tcurr[j] = Math.min(del, ins, sub);\n\t\t}\n\t\tprev = curr;\n\t}\n\n\treturn prev[n] ?? 0;\n}\n\n/**\n * Similarity in `[0, 1]` combining edit distance with `_`-token overlap, so both\n * near-typos (a missing underscore) and renames (`DATABASE_URL` ~ `DB_URL`,\n * which share the `URL` token) are caught.\n */\nfunction similarity(a: string, b: string): number {\n\tconst editSim = 1 - levenshtein(a, b) / Math.max(a.length, b.length, 1);\n\n\tconst ta = new Set(a.split('_').filter(Boolean));\n\tconst tb = new Set(b.split('_').filter(Boolean));\n\tconst shared = [...ta].filter((t) => tb.has(t)).length;\n\tconst union = new Set([...ta, ...tb]).size || 1;\n\tconst tokenSim = shared / union;\n\n\t// Nudge token-overlap matches ahead of coincidental edit-distance ones, so a\n\t// rename like DATABASE_URL prefers DB_URL (shares `URL`) over DB_PASSWORD.\n\treturn Math.max(editSim, tokenSim * 1.15);\n}\n\n/**\n * Returns the nearest available variables to `missing`, best first, limited to\n * those above {@link SUGGESTION_THRESHOLD}.\n */\nfunction suggestionsFor(\n\tmissing: string,\n\tavailable: readonly string[],\n\tmax = 1,\n): string[] {\n\treturn available\n\t\t.map((candidate) => ({ candidate, score: similarity(missing, candidate) }))\n\t\t.filter((s) => s.score >= SUGGESTION_THRESHOLD)\n\t\t.sort((a, b) => b.score - a.score)\n\t\t.slice(0, max)\n\t\t.map((s) => s.candidate);\n}\n\n/**\n * Thrown when a deployable unit requires environment variables its links do not\n * provide. Carries the structured `missing`/`available`/`suggestions` so callers\n * can inspect the failure programmatically, not just read the message.\n */\nexport class EnvValidationError extends Error {\n\treadonly isEnvValidationError = true;\n\treadonly missing: string[];\n\treadonly available: string[];\n\treadonly suggestions: Record<string, string[]>;\n\treadonly context?: string;\n\n\tconstructor(args: {\n\t\tmissing: string[];\n\t\tavailable: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}) {\n\t\tsuper(EnvValidationError.format(args));\n\t\tthis.name = 'EnvValidationError';\n\t\tthis.missing = args.missing;\n\t\tthis.available = args.available;\n\t\tthis.suggestions = args.suggestions;\n\t\tthis.context = args.context;\n\t\t// V8-only; keeps the constructor out of the stack trace.\n\t\t(\n\t\t\tError as unknown as {\n\t\t\t\tcaptureStackTrace?(target: object, ctor?: unknown): void;\n\t\t\t}\n\t\t).captureStackTrace?.(this, EnvValidationError);\n\t}\n\n\tprivate static format(args: {\n\t\tmissing: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}): string {\n\t\tconst { missing, linkVars, suggestions, context } = args;\n\t\tconst who = context ? `'${context}'` : 'a deployable unit';\n\n\t\tconst width = Math.max(...missing.map((v) => v.length));\n\t\tconst lines = missing.map((v) => {\n\t\t\tconst hints = suggestions[v] ?? [];\n\t\t\tconst hint = hints.length ? `(did you mean ${hints.join(' or ')}?)` : '';\n\t\t\treturn ` - ${v.padEnd(width)} ${hint}`.trimEnd();\n\t\t});\n\n\t\tlet provided: string;\n\t\tif (linkVars.length === 0) {\n\t\t\tprovided = '(no links provide environment variables)';\n\t\t} else {\n\t\t\tconst shown = linkVars.slice(0, MAX_LISTED_VARS).join(', ');\n\t\t\tconst extra =\n\t\t\t\tlinkVars.length > MAX_LISTED_VARS\n\t\t\t\t\t? ` ...(+${linkVars.length - MAX_LISTED_VARS})`\n\t\t\t\t\t: '';\n\t\t\tprovided = `Provided by links: ${shown}${extra}`;\n\t\t}\n\n\t\treturn `${who} is missing required env vars:\\n${lines.join('\\n')}\\n\\n${provided}`;\n\t}\n}\n\n/**\n * Derives the set of environment-variable **keys** a group of linked resources\n * will produce at runtime — without resolving any value.\n *\n * This reuses the runtime resolvers (`sstResolvers`) via {@link EnvironmentBuilder},\n * so the keys computed here are exactly the keys a deployed function receives:\n * the validator and the runtime resolution share a single source of truth and\n * cannot drift. Because every resolver's output keys depend only on the record\n * key and the resource `type` (never the value), each resource is reduced to\n * `{ type }` before building, so no SST `Output` is ever read.\n *\n * @example\n * resolveEnvKeys({ db: { type: ResourceType.Postgres } });\n * // ['DB_NAME', 'DB_HOST', 'DB_PASSWORD', 'DB_PORT', 'DB_USERNAME', 'DB_URL']\n */\nexport function resolveEnvKeys(record: LinkRecord): string[] {\n\tconst typeOnly: Record<string, InputValue> = {};\n\tfor (const [key, value] of Object.entries(record)) {\n\t\ttypeOnly[key] = typeof value === 'string' ? '' : { type: value.type };\n\t}\n\treturn Object.keys(new EnvironmentBuilder(typeOnly, sstResolvers).build());\n}\n\n/**\n * Validates that the environment variables a deployable unit requires are\n * actually provided by its linked resources — at infra time, before deploy.\n *\n * Available variables are the union of the keys derived from `links`\n * ({@link resolveEnvKeys}), the chosen platform's runtime variables (only when\n * `options.platform` is set — nothing is assumed), and any `options.whitelist`\n * (e.g. the keys of a function's explicit `environment`). A requested variable\n * suffixed with `?` is treated as optional and never causes a failure.\n *\n * @example\n * const validator = new EnvValidator(\n * { db: { type: ResourceType.Postgres } },\n * { platform: 'aws', whitelist: ['APP_NAME'], context: 'orders-fn' },\n * );\n * validator.assert(['DB_HOST', 'AWS_REGION', 'APP_NAME', 'SENTRY_DSN?']); // ok\n * validator.assert(['DATABASE_URL']); // throws EnvValidationError (did you mean DB_URL?)\n */\nexport class EnvValidator {\n\t/** Every variable available — link-derived, platform, and extra whitelist. */\n\treadonly availableVars: string[];\n\t/** Just the variables the links provide (used for error context). */\n\treadonly linkVars: string[];\n\treadonly context?: string;\n\tprivate readonly availableSet: Set<string>;\n\t/** Per-link (record key → its env-var keys), for least-privilege filtering. */\n\tprivate readonly linkVarsByName: Map<string, string[]>;\n\n\tconstructor(links: LinkRecord, options: EnvValidatorOptions = {}) {\n\t\tconst { platform, whitelist = [], context } = options;\n\t\tthis.context = context;\n\t\tthis.linkVarsByName = new Map(\n\t\t\tObject.entries(links).map(([name, value]) => [\n\t\t\t\tname,\n\t\t\t\tresolveEnvKeys({ [name]: value }),\n\t\t\t]),\n\t\t);\n\t\tthis.linkVars = [...this.linkVarsByName.values()].flat();\n\t\tthis.availableVars = [\n\t\t\t...this.linkVars,\n\t\t\t...(platform ? PLATFORM_ENV_VARS[platform] : []),\n\t\t\t...whitelist,\n\t\t];\n\t\tthis.availableSet = new Set(this.availableVars);\n\t}\n\n\t/**\n\t * Returns the names of the links that provide at least one of the requested\n\t * variables — so a construct can attach only the links a unit actually needs\n\t * (least privilege) rather than the whole pool. Trailing `?` is ignored.\n\t */\n\tgetProvidersForEnvVars(requestedEnvVars: readonly string[]): string[] {\n\t\tconst requested = new Set(\n\t\t\trequestedEnvVars.map((v) => (v.endsWith('?') ? v.slice(0, -1) : v)),\n\t\t);\n\t\tconst providers: string[] = [];\n\t\tfor (const [name, vars] of this.linkVarsByName) {\n\t\t\tif (vars.some((v) => requested.has(v))) providers.push(name);\n\t\t}\n\t\treturn providers;\n\t}\n\n\t/**\n\t * Checks every requested variable against the available set. Variables\n\t * ending in `?` are optional and never reported as invalid. Invalid\n\t * variables come back with their nearest available matches.\n\t */\n\tvalidate(requestedEnvVars: readonly string[]): ValidationResult {\n\t\tconst invalidVars = requestedEnvVars.filter((envVar) => {\n\t\t\tif (envVar.endsWith('?')) return false;\n\t\t\treturn !this.availableSet.has(envVar);\n\t\t});\n\n\t\tconst suggestions: Record<string, string[]> = {};\n\t\tfor (const envVar of invalidVars) {\n\t\t\tconst matches = suggestionsFor(envVar, this.availableVars);\n\t\t\tif (matches.length) suggestions[envVar] = matches;\n\t\t}\n\n\t\treturn {\n\t\t\tvalid: invalidVars.length === 0,\n\t\t\tinvalidVars,\n\t\t\tavailableVars: this.availableVars,\n\t\t\tsuggestions,\n\t\t};\n\t}\n\n\t/**\n\t * Asserts that every requested variable is available, throwing an\n\t * {@link EnvValidationError} otherwise. Intended to run in a construct's\n\t * constructor so a misconfigured `sst.config.ts` fails at synth time, before\n\t * any AWS call.\n\t */\n\tassert(requestedEnvVars: readonly string[]): void {\n\t\tconst { valid, invalidVars, suggestions } = this.validate(requestedEnvVars);\n\n\t\tif (!valid) {\n\t\t\tthrow new EnvValidationError({\n\t\t\t\tmissing: invalidVars,\n\t\t\t\tavailable: this.availableVars,\n\t\t\t\tlinkVars: this.linkVars,\n\t\t\t\tsuggestions,\n\t\t\t\tcontext: this.context,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Whether a single variable is available. Does not treat a trailing `?` as\n\t * optional — pass the bare name.\n\t */\n\thas(envVar: string): boolean {\n\t\treturn this.availableSet.has(envVar);\n\t}\n}\n","// Re-export everything from SstEnvironmentBuilder\n\n// Re-export types from EnvironmentBuilder\nexport type {\n\tEnvironmentBuilderOptions,\n\tEnvRecord,\n\tEnvValue,\n} from './EnvironmentBuilder';\n\n// Re-export environmentCase from EnvironmentBuilder\nexport { environmentCase } from './EnvironmentBuilder';\nexport {\n\ttype ApiGatewayV2,\n\ttype Bucket,\n\ttype Dynamo,\n\ttype Function,\n\ttype Postgres,\n\ttype Queue,\n\ttype ResourceProcessor,\n\tResourceType,\n\ttype Secret,\n\ttype SnsTopic,\n\tSstEnvironmentBuilder,\n\ttype SstResource,\n\tsstResolvers,\n\ttype Vpc,\n} from './SstEnvironmentBuilder';\n\nexport {\n\tAWS_RUNTIME_ENV_VARS,\n\tCLOUDFLARE_RUNTIME_ENV_VARS,\n\tEnvValidationError,\n\tEnvValidator,\n\ttype EnvValidatorOptions,\n\tGCP_RUNTIME_ENV_VARS,\n\ttype LinkRecord,\n\tPLATFORM_ENV_VARS,\n\ttype Platform,\n\tplatformEnvVars,\n\tresolveEnvKeys,\n\ttype ValidationResult,\n} from './SstEnvValidator';\n\n// Import for deprecated function\nimport {\n\tSstEnvironmentBuilder,\n\ttype SstResource,\n} from './SstEnvironmentBuilder';\n\n/**\n * @deprecated Use `new SstEnvironmentBuilder(record).build()` instead.\n *\n * Normalizes SST resources and plain strings into environment variables.\n * Processes resources based on their type and converts names to environment case.\n *\n * @param record - Object containing resources and/or string values\n * @returns Normalized environment variables object\n *\n * @example\n * // Old usage (deprecated):\n * normalizeResourceEnv({ database: postgresResource })\n *\n * // New usage:\n * new SstEnvironmentBuilder({ database: postgresResource }).build()\n */\nexport function normalizeResourceEnv(\n\trecord: Record<string, SstResource | string>,\n): Record<string, string | number | boolean | Record<string, unknown>> {\n\treturn new SstEnvironmentBuilder(record).build();\n}\n\n// Keep Resource type as deprecated alias for backwards compatibility\n/**\n * @deprecated Use `SstResource` instead.\n */\nexport type Resource = SstResource;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sst.mjs","names":[],"sources":["../src/SstEnvironmentBuilder.ts","../src/SstEnvValidator.ts","../src/sst.ts"],"sourcesContent":["import {\n\tEnvironmentBuilder,\n\ttype EnvironmentBuilderOptions,\n\ttype EnvironmentResolver,\n\ttype EnvRecord,\n\ttype InputValue,\n\ttype Resolvers,\n} from './EnvironmentBuilder';\n\n/**\n * Enumeration of supported SST (Serverless Stack Toolkit) resource types.\n * Used to identify and process different AWS and SST resources.\n */\nexport enum ResourceType {\n\t// Legacy format (dot notation)\n\tApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n\tPostgres = 'sst.aws.Postgres',\n\tFunction = 'sst.aws.Function',\n\tObjectStorage = 'sst.aws.Bucket',\n\tVpc = 'sst.aws.Vpc',\n\tSecret = 'sst.sst.Secret',\n\tDynamo = 'sst.aws.Dynamo',\n\tQueue = 'sst.aws.Queue',\n\n\t// Modern format (colon notation)\n\tSSTSecret = 'sst:sst:Secret',\n\tSSTFunction = 'sst:sst:Function',\n\tSSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n\tSSTPostgres = 'sst:aws:Postgres',\n\tSSTObjectStorage = 'sst:aws:Bucket',\n\tSnsTopic = 'sst:aws:SnsTopic',\n\tSSTDynamo = 'sst:aws:Dynamo',\n\tSSTQueue = 'sst:aws:Queue',\n\t// A distribution, twice over: a file server and a static site are the same\n\t// infrastructure with different contents behind it, and they are separate\n\t// entries because what they provide is read under different ids, not\n\t// because SST builds them differently.\n\tFileServer = 'sst:aws:Router',\n\tStaticSite = 'sst:aws:StaticSite',\n\t// Neither is an SST component: mail is an IAM chain and a composed URL, and\n\t// a cache is whatever the selected backend turned out to be.\n\tEmail = 'gkm:aws:Email',\n\tCache = 'gkm:aws:Cache',\n}\n\n/**\n * AWS API Gateway V2 resource type.\n * Represents an HTTP/WebSocket API.\n */\nexport type ApiGatewayV2 = {\n\ttype: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n\turl: string;\n};\n\n/**\n * PostgreSQL database resource type.\n * Contains all connection details needed to connect to the database.\n */\nexport type Postgres = {\n\ttype: ResourceType.Postgres | ResourceType.SSTPostgres;\n\tdatabase: string;\n\thost: string;\n\tpassword: string;\n\tport: number;\n\tusername: string;\n};\n\n/**\n * AWS Lambda Function resource type.\n */\nexport type Function = {\n\ttype: ResourceType.Function | ResourceType.SSTFunction;\n\tname: string;\n};\n\n/**\n * AWS S3 Bucket resource type.\n */\nexport type Bucket = {\n\ttype: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;\n\tname: string;\n\t/**\n\t * Supplied by `@geekmidas/cloud`'s ObjectStorage, which widens SST's link to\n\t * carry them — a bucket may not be in the reader's region, and the URL is\n\t * composed where the resource's shape is known.\n\t */\n\tregion?: string;\n\turl?: string;\n};\n\n/**\n * AWS VPC (Virtual Private Cloud) resource type.\n */\nexport type Vpc = {\n\ttype: ResourceType.Vpc;\n\tbastion: string;\n};\n\n/**\n * Secret resource type for storing sensitive values.\n */\nexport type Secret = {\n\ttype: ResourceType.Secret | ResourceType.SSTSecret;\n\tvalue: string;\n};\n\n/**\n * AWS SNS Topic resource type.\n */\nexport type SnsTopic = {\n\ttype: ResourceType.SnsTopic;\n\tarn: string;\n};\n\n/**\n * AWS SQS Queue resource type.\n */\nexport type Queue = {\n\ttype: ResourceType.Queue | ResourceType.SSTQueue;\n\turl: string;\n\tarn: string;\n};\n\n/**\n * AWS DynamoDB Table resource type.\n */\nexport type Dynamo = {\n\ttype: ResourceType.Dynamo | ResourceType.SSTDynamo;\n\tname: string;\n};\n\n/**\n * Union type of all supported SST resource types.\n */\nexport type SstResource =\n\t| ApiGatewayV2\n\t| Postgres\n\t| Function\n\t| Bucket\n\t| Vpc\n\t| Secret\n\t| SnsTopic\n\t| Queue\n\t| Dynamo;\n\n// Value types without the `type` key (for resolver parameters)\ntype SecretValue = Omit<Secret, 'type'>;\ntype PostgresValue = Omit<Postgres, 'type'>;\ntype BucketValue = Omit<Bucket, 'type'>;\ntype SnsTopicValue = Omit<SnsTopic, 'type'>;\ntype QueueValue = Omit<Queue, 'type'>;\ntype DynamoValue = Omit<Dynamo, 'type'>;\n\n/**\n * Function type for processing a specific resource type into environment variables.\n *\n * @template K - The specific resource type (without `type` key)\n * @param name - The resource name\n * @param value - The resource value (without `type` key)\n * @returns Object mapping environment variable names to values\n */\nexport type ResourceProcessor<K> = (name: string, value: K) => EnvRecord;\n\n// SST Resource Resolvers (receive values without `type` key)\n\nconst secretResolver = (name: string, value: SecretValue) => ({\n\t[name]: value.value,\n});\n\nconst postgresResolver = (key: string, value: PostgresValue) => ({\n\t[`${key}Name`]: value.database,\n\t[`${key}Host`]: value.host,\n\t[`${key}Password`]: value.password,\n\t[`${key}Port`]: value.port,\n\t[`${key}Username`]: value.username,\n\t[`${key}Url`]: `postgresql://${encodeURIComponent(value.username)}:${encodeURIComponent(value.password)}@${value.host}:${value.port}/${value.database}`,\n});\n\nconst bucketResolver = (name: string, value: BucketValue) => ({\n\t[`${name}Name`]: value.name,\n\t// The single URL a construct reads. Composed by the component, which knows\n\t// its own shape; this only renames it into env case. Always emitted, even\n\t// when absent, so `resolveEnvKeys` can derive the key from the link's type\n\t// alone — a bucket linked without our component yields an empty one.\n\t[`${name}Url`]: value.url ?? '',\n});\n\nconst topicResolver = (name: string, value: SnsTopicValue) => ({\n\t[`${name}Arn`]: value.arn,\n\t// A publisher connection string for `@geekmidas/events` (SNS); region is\n\t// resolved from the ARN / AWS_REGION at runtime.\n\t[`${name}PublisherConnectionString`]: `sns://?topicArn=${encodeURIComponent(value.arn)}`,\n});\n\nconst queueResolver = (name: string, value: QueueValue) => ({\n\t[`${name}Url`]: value.url,\n\t[`${name}Arn`]: value.arn,\n\t// A publisher connection string for `@geekmidas/events` (SQS); region is\n\t// resolved from the URL / AWS_REGION at runtime.\n\t[`${name}PublisherConnectionString`]: `sqs://?queueUrl=${encodeURIComponent(value.url)}`,\n});\n\nconst dynamoResolver = (name: string, value: DynamoValue) => ({\n\t[`${name}Name`]: value.name,\n});\n\nconst noopResolver = () => ({});\n\n/**\n * Pre-configured resolvers for all SST resource types.\n */\nexport const sstResolvers: Resolvers = {\n\t// Legacy format\n\t[ResourceType.ApiGatewayV2]: noopResolver,\n\t[ResourceType.Function]: noopResolver,\n\t[ResourceType.Vpc]: noopResolver,\n\t[ResourceType.Secret]: secretResolver,\n\t[ResourceType.Postgres]: postgresResolver,\n\t[ResourceType.ObjectStorage]: bucketResolver,\n\t[ResourceType.Dynamo]: dynamoResolver,\n\t[ResourceType.Queue]: queueResolver,\n\n\t// Modern format\n\t[ResourceType.SSTSecret]: secretResolver,\n\t[ResourceType.SSTObjectStorage]: bucketResolver,\n\t[ResourceType.SSTFunction]: noopResolver,\n\t[ResourceType.SSTPostgres]: postgresResolver,\n\t[ResourceType.SSTApiGatewayV2]: noopResolver,\n\t[ResourceType.SnsTopic]: topicResolver,\n\t[ResourceType.SSTDynamo]: dynamoResolver,\n\t[ResourceType.SSTQueue]: queueResolver,\n};\n\n/**\n * All known SST resource type strings.\n */\ntype SstResourceTypeString = `${ResourceType}`;\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * Extracts only the custom (non-SST) type values from a record.\n */\ntype CustomTypeValues<TRecord extends Record<string, InputValue>> = Exclude<\n\tAllTypeValues<TRecord>,\n\tSstResourceTypeString\n>;\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers for custom (non-SST) types in the input record.\n */\ntype CustomResolvers<TRecord extends Record<string, InputValue>> =\n\tCustomTypeValues<TRecord> extends never\n\t\t? Resolvers | undefined\n\t\t: {\n\t\t\t\t[TType in CustomTypeValues<TRecord>]: EnvironmentResolver<\n\t\t\t\t\tValueForType<TRecord, TType>\n\t\t\t\t>;\n\t\t\t};\n\n/**\n * SST-specific environment builder with built-in resolvers for all known\n * SST resource types.\n *\n * Wraps the generic EnvironmentBuilder with pre-configured SST resolvers.\n *\n * @template TRecord - The input record type for type inference\n *\n * @example\n * ```typescript\n * const env = new SstEnvironmentBuilder({\n * database: { type: 'sst:aws:Postgres', host: '...', ... },\n * apiKey: { type: 'sst:sst:Secret', value: 'secret' },\n * appName: 'my-app',\n * }).build();\n *\n * // With custom resolvers (typed based on input)\n * const env = new SstEnvironmentBuilder(\n * {\n * database: postgresResource,\n * custom: { type: 'my-custom' as const, data: 'foo' },\n * },\n * {\n * // TypeScript requires 'my-custom' resolver with typed value\n * 'my-custom': (key, value) => ({ [`${key}Data`]: value.data }),\n * }\n * ).build();\n * ```\n */\nexport class SstEnvironmentBuilder<\n\tTRecord extends Record<string, SstResource | InputValue | string>,\n> {\n\tprivate readonly builder: EnvironmentBuilder<\n\t\tRecord<string, InputValue>,\n\t\tResolvers\n\t>;\n\n\t/**\n\t * Create a new SST environment builder.\n\t *\n\t * @param record - Object containing SST resources, custom resources, and/or string values\n\t * @param additionalResolvers - Optional custom resolvers (typed based on custom types in record)\n\t * @param options - Optional configuration options\n\t */\n\tconstructor(\n\t\trecord: TRecord,\n\t\tadditionalResolvers?: CustomResolvers<TRecord>,\n\t\toptions?: EnvironmentBuilderOptions,\n\t) {\n\t\t// Merge resolvers with custom ones taking precedence\n\t\tconst mergedResolvers: Resolvers = additionalResolvers\n\t\t\t? { ...sstResolvers, ...additionalResolvers }\n\t\t\t: sstResolvers;\n\n\t\tthis.builder = new EnvironmentBuilder(\n\t\t\trecord as Record<string, InputValue>,\n\t\t\tmergedResolvers,\n\t\t\toptions,\n\t\t);\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\treturn this.builder.build();\n\t}\n}\n\nexport type {\n\tEnvironmentBuilderOptions,\n\tEnvRecord,\n\tEnvValue,\n} from './EnvironmentBuilder';\n// Re-export useful types\nexport { environmentCase } from './EnvironmentBuilder';\n","import { EnvironmentBuilder, type InputValue } from './EnvironmentBuilder';\nimport { type SstResource, sstResolvers } from './SstEnvironmentBuilder';\n\n/**\n * Variables AWS Lambda injects into the runtime. Always valid on AWS, but never\n * assumed — opt in via `platform: 'aws'` or by spreading {@link AWS_RUNTIME_ENV_VARS}\n * into `whitelist`.\n */\nexport const AWS_RUNTIME_ENV_VARS = [\n\t'AWS_REGION',\n\t'AWS_DEFAULT_REGION',\n\t'AWS_ENDPOINT_URL',\n\t'AWS_ENDPOINT',\n\t'AWS_ACCESS_KEY_ID',\n\t'AWS_SECRET_ACCESS_KEY',\n\t'AWS_SESSION_TOKEN',\n\t'AWS_LAMBDA_FUNCTION_NAME',\n\t'AWS_LAMBDA_FUNCTION_VERSION',\n] as const;\n\n/**\n * Variables GCP injects into Cloud Functions / Cloud Run.\n */\nexport const GCP_RUNTIME_ENV_VARS = [\n\t'GOOGLE_CLOUD_PROJECT',\n\t'GCP_PROJECT',\n\t'FUNCTION_TARGET',\n\t'FUNCTION_SIGNATURE_TYPE',\n\t'K_SERVICE',\n\t'K_REVISION',\n\t'K_CONFIGURATION',\n\t'PORT',\n] as const;\n\n/**\n * Variables Cloudflare exposes to Workers. Workers inject almost nothing into\n * the global env, so this is intentionally minimal.\n */\nexport const CLOUDFLARE_RUNTIME_ENV_VARS = [\n\t'CF_PAGES',\n\t'CF_PAGES_URL',\n] as const;\n\n/**\n * Registry of platform → always-valid runtime variables. Export, don't assume:\n * a caller states the platform it deploys to and the matching set is trusted.\n */\nexport const PLATFORM_ENV_VARS = {\n\taws: AWS_RUNTIME_ENV_VARS,\n\tgcp: GCP_RUNTIME_ENV_VARS,\n\tcloudflare: CLOUDFLARE_RUNTIME_ENV_VARS,\n} as const;\n\nexport type Platform = keyof typeof PLATFORM_ENV_VARS;\n\n/**\n * The always-valid runtime variables for a platform. The \"whitelist construct\":\n * resolve a platform to its set, to spread into `whitelist` or compare against.\n */\nexport function platformEnvVars(platform: Platform): readonly string[] {\n\treturn PLATFORM_ENV_VARS[platform];\n}\n\n/** How many link-provided vars to list in an error before truncating. */\nconst MAX_LISTED_VARS = 8;\n\n/** Minimum similarity for a variable to be offered as a \"did you mean\". */\nconst SUGGESTION_THRESHOLD = 0.3;\n\n/**\n * Input shape for the validator: the same record `SstEnvironmentBuilder`\n * accepts — keyed by resource name, valued by an SST resource (or a plain\n * string for pass-through env vars).\n */\nexport type LinkRecord = Record<string, SstResource | InputValue | string>;\n\nexport interface ValidationResult {\n\tvalid: boolean;\n\t/** Requested variables that are not available (excluding optional `?` vars). */\n\tinvalidVars: string[];\n\t/** Every variable the links + whitelist make available. */\n\tavailableVars: string[];\n\t/** Nearest available matches for each invalid variable (best first). */\n\tsuggestions: Record<string, string[]>;\n}\n\nexport interface EnvValidatorOptions {\n\t/**\n\t * Platform whose runtime-injected variables are always valid. Omit to assume\n\t * none — the validator never bakes in a platform's variables.\n\t */\n\tplatform?: Platform;\n\t/**\n\t * Extra always-valid variables in addition to the platform set — typically\n\t * the keys of a function's explicit `environment`.\n\t */\n\twhitelist?: readonly string[];\n\t/**\n\t * Label for the deployable unit (e.g. a function name), used in error\n\t * messages so a failure points at exactly one unit.\n\t */\n\tcontext?: string;\n}\n\n/**\n * Levenshtein edit distance between two strings.\n */\nfunction levenshtein(a: string, b: string): number {\n\tconst m = a.length;\n\tconst n = b.length;\n\tif (m === 0) return n;\n\tif (n === 0) return m;\n\n\tlet prev = Array.from({ length: n + 1 }, (_, i) => i);\n\n\tfor (let i = 1; i <= m; i++) {\n\t\tconst curr: number[] = [i];\n\t\tfor (let j = 1; j <= n; j++) {\n\t\t\tconst cost = a[i - 1] === b[j - 1] ? 0 : 1;\n\t\t\tconst del = (prev[j] ?? 0) + 1;\n\t\t\tconst ins = (curr[j - 1] ?? 0) + 1;\n\t\t\tconst sub = (prev[j - 1] ?? 0) + cost;\n\t\t\tcurr[j] = Math.min(del, ins, sub);\n\t\t}\n\t\tprev = curr;\n\t}\n\n\treturn prev[n] ?? 0;\n}\n\n/**\n * Similarity in `[0, 1]` combining edit distance with `_`-token overlap, so both\n * near-typos (a missing underscore) and renames (`DATABASE_URL` ~ `DB_URL`,\n * which share the `URL` token) are caught.\n */\nfunction similarity(a: string, b: string): number {\n\tconst editSim = 1 - levenshtein(a, b) / Math.max(a.length, b.length, 1);\n\n\tconst ta = new Set(a.split('_').filter(Boolean));\n\tconst tb = new Set(b.split('_').filter(Boolean));\n\tconst shared = [...ta].filter((t) => tb.has(t)).length;\n\tconst union = new Set([...ta, ...tb]).size || 1;\n\tconst tokenSim = shared / union;\n\n\t// Nudge token-overlap matches ahead of coincidental edit-distance ones, so a\n\t// rename like DATABASE_URL prefers DB_URL (shares `URL`) over DB_PASSWORD.\n\treturn Math.max(editSim, tokenSim * 1.15);\n}\n\n/**\n * Returns the nearest available variables to `missing`, best first, limited to\n * those above {@link SUGGESTION_THRESHOLD}.\n */\nfunction suggestionsFor(\n\tmissing: string,\n\tavailable: readonly string[],\n\tmax = 1,\n): string[] {\n\treturn available\n\t\t.map((candidate) => ({ candidate, score: similarity(missing, candidate) }))\n\t\t.filter((s) => s.score >= SUGGESTION_THRESHOLD)\n\t\t.sort((a, b) => b.score - a.score)\n\t\t.slice(0, max)\n\t\t.map((s) => s.candidate);\n}\n\n/**\n * Thrown when a deployable unit requires environment variables its links do not\n * provide. Carries the structured `missing`/`available`/`suggestions` so callers\n * can inspect the failure programmatically, not just read the message.\n */\nexport class EnvValidationError extends Error {\n\treadonly isEnvValidationError = true;\n\treadonly missing: string[];\n\treadonly available: string[];\n\treadonly suggestions: Record<string, string[]>;\n\treadonly context?: string;\n\n\tconstructor(args: {\n\t\tmissing: string[];\n\t\tavailable: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}) {\n\t\tsuper(EnvValidationError.format(args));\n\t\tthis.name = 'EnvValidationError';\n\t\tthis.missing = args.missing;\n\t\tthis.available = args.available;\n\t\tthis.suggestions = args.suggestions;\n\t\tthis.context = args.context;\n\t\t// V8-only; keeps the constructor out of the stack trace.\n\t\t(\n\t\t\tError as unknown as {\n\t\t\t\tcaptureStackTrace?(target: object, ctor?: unknown): void;\n\t\t\t}\n\t\t).captureStackTrace?.(this, EnvValidationError);\n\t}\n\n\tprivate static format(args: {\n\t\tmissing: string[];\n\t\tlinkVars: string[];\n\t\tsuggestions: Record<string, string[]>;\n\t\tcontext?: string;\n\t}): string {\n\t\tconst { missing, linkVars, suggestions, context } = args;\n\t\tconst who = context ? `'${context}'` : 'a deployable unit';\n\n\t\tconst width = Math.max(...missing.map((v) => v.length));\n\t\tconst lines = missing.map((v) => {\n\t\t\tconst hints = suggestions[v] ?? [];\n\t\t\tconst hint = hints.length ? `(did you mean ${hints.join(' or ')}?)` : '';\n\t\t\treturn ` - ${v.padEnd(width)} ${hint}`.trimEnd();\n\t\t});\n\n\t\tlet provided: string;\n\t\tif (linkVars.length === 0) {\n\t\t\tprovided = '(no links provide environment variables)';\n\t\t} else {\n\t\t\tconst shown = linkVars.slice(0, MAX_LISTED_VARS).join(', ');\n\t\t\tconst extra =\n\t\t\t\tlinkVars.length > MAX_LISTED_VARS\n\t\t\t\t\t? ` ...(+${linkVars.length - MAX_LISTED_VARS})`\n\t\t\t\t\t: '';\n\t\t\tprovided = `Provided by links: ${shown}${extra}`;\n\t\t}\n\n\t\treturn `${who} is missing required env vars:\\n${lines.join('\\n')}\\n\\n${provided}`;\n\t}\n}\n\n/**\n * Derives the set of environment-variable **keys** a group of linked resources\n * will produce at runtime — without resolving any value.\n *\n * This reuses the runtime resolvers (`sstResolvers`) via {@link EnvironmentBuilder},\n * so the keys computed here are exactly the keys a deployed function receives:\n * the validator and the runtime resolution share a single source of truth and\n * cannot drift. Because every resolver's output keys depend only on the record\n * key and the resource `type` (never the value), each resource is reduced to\n * `{ type }` before building, so no SST `Output` is ever read.\n *\n * @example\n * resolveEnvKeys({ db: { type: ResourceType.Postgres } });\n * // ['DB_NAME', 'DB_HOST', 'DB_PASSWORD', 'DB_PORT', 'DB_USERNAME', 'DB_URL']\n */\nexport function resolveEnvKeys(record: LinkRecord): string[] {\n\tconst typeOnly: Record<string, InputValue> = {};\n\tfor (const [key, value] of Object.entries(record)) {\n\t\ttypeOnly[key] = typeof value === 'string' ? '' : { type: value.type };\n\t}\n\treturn Object.keys(new EnvironmentBuilder(typeOnly, sstResolvers).build());\n}\n\n/**\n * Validates that the environment variables a deployable unit requires are\n * actually provided by its linked resources — at infra time, before deploy.\n *\n * Available variables are the union of the keys derived from `links`\n * ({@link resolveEnvKeys}), the chosen platform's runtime variables (only when\n * `options.platform` is set — nothing is assumed), and any `options.whitelist`\n * (e.g. the keys of a function's explicit `environment`). A requested variable\n * suffixed with `?` is treated as optional and never causes a failure.\n *\n * @example\n * const validator = new EnvValidator(\n * { db: { type: ResourceType.Postgres } },\n * { platform: 'aws', whitelist: ['APP_NAME'], context: 'orders-fn' },\n * );\n * validator.assert(['DB_HOST', 'AWS_REGION', 'APP_NAME', 'SENTRY_DSN?']); // ok\n * validator.assert(['DATABASE_URL']); // throws EnvValidationError (did you mean DB_URL?)\n */\nexport class EnvValidator {\n\t/** Every variable available — link-derived, platform, and extra whitelist. */\n\treadonly availableVars: string[];\n\t/** Just the variables the links provide (used for error context). */\n\treadonly linkVars: string[];\n\treadonly context?: string;\n\tprivate readonly availableSet: Set<string>;\n\t/** Per-link (record key → its env-var keys), for least-privilege filtering. */\n\tprivate readonly linkVarsByName: Map<string, string[]>;\n\n\tconstructor(links: LinkRecord, options: EnvValidatorOptions = {}) {\n\t\tconst { platform, whitelist = [], context } = options;\n\t\tthis.context = context;\n\t\tthis.linkVarsByName = new Map(\n\t\t\tObject.entries(links).map(([name, value]) => [\n\t\t\t\tname,\n\t\t\t\tresolveEnvKeys({ [name]: value }),\n\t\t\t]),\n\t\t);\n\t\tthis.linkVars = [...this.linkVarsByName.values()].flat();\n\t\tthis.availableVars = [\n\t\t\t...this.linkVars,\n\t\t\t...(platform ? PLATFORM_ENV_VARS[platform] : []),\n\t\t\t...whitelist,\n\t\t];\n\t\tthis.availableSet = new Set(this.availableVars);\n\t}\n\n\t/**\n\t * Returns the names of the links that provide at least one of the requested\n\t * variables — so a construct can attach only the links a unit actually needs\n\t * (least privilege) rather than the whole pool. Trailing `?` is ignored.\n\t */\n\tgetProvidersForEnvVars(requestedEnvVars: readonly string[]): string[] {\n\t\tconst requested = new Set(\n\t\t\trequestedEnvVars.map((v) => (v.endsWith('?') ? v.slice(0, -1) : v)),\n\t\t);\n\t\tconst providers: string[] = [];\n\t\tfor (const [name, vars] of this.linkVarsByName) {\n\t\t\tif (vars.some((v) => requested.has(v))) providers.push(name);\n\t\t}\n\t\treturn providers;\n\t}\n\n\t/**\n\t * Checks every requested variable against the available set. Variables\n\t * ending in `?` are optional and never reported as invalid. Invalid\n\t * variables come back with their nearest available matches.\n\t */\n\tvalidate(requestedEnvVars: readonly string[]): ValidationResult {\n\t\tconst invalidVars = requestedEnvVars.filter((envVar) => {\n\t\t\tif (envVar.endsWith('?')) return false;\n\t\t\treturn !this.availableSet.has(envVar);\n\t\t});\n\n\t\tconst suggestions: Record<string, string[]> = {};\n\t\tfor (const envVar of invalidVars) {\n\t\t\tconst matches = suggestionsFor(envVar, this.availableVars);\n\t\t\tif (matches.length) suggestions[envVar] = matches;\n\t\t}\n\n\t\treturn {\n\t\t\tvalid: invalidVars.length === 0,\n\t\t\tinvalidVars,\n\t\t\tavailableVars: this.availableVars,\n\t\t\tsuggestions,\n\t\t};\n\t}\n\n\t/**\n\t * Asserts that every requested variable is available, throwing an\n\t * {@link EnvValidationError} otherwise. Intended to run in a construct's\n\t * constructor so a misconfigured `sst.config.ts` fails at synth time, before\n\t * any AWS call.\n\t */\n\tassert(requestedEnvVars: readonly string[]): void {\n\t\tconst { valid, invalidVars, suggestions } = this.validate(requestedEnvVars);\n\n\t\tif (!valid) {\n\t\t\tthrow new EnvValidationError({\n\t\t\t\tmissing: invalidVars,\n\t\t\t\tavailable: this.availableVars,\n\t\t\t\tlinkVars: this.linkVars,\n\t\t\t\tsuggestions,\n\t\t\t\tcontext: this.context,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Whether a single variable is available. Does not treat a trailing `?` as\n\t * optional — pass the bare name.\n\t */\n\thas(envVar: string): boolean {\n\t\treturn this.availableSet.has(envVar);\n\t}\n}\n","// Re-export everything from SstEnvironmentBuilder\n\n// Re-export types from EnvironmentBuilder\nexport type {\n\tEnvironmentBuilderOptions,\n\tEnvRecord,\n\tEnvValue,\n} from './EnvironmentBuilder';\n\n// Re-export environmentCase from EnvironmentBuilder\nexport { environmentCase } from './EnvironmentBuilder';\nexport {\n\ttype ApiGatewayV2,\n\ttype Bucket,\n\ttype Dynamo,\n\ttype Function,\n\ttype Postgres,\n\ttype Queue,\n\ttype ResourceProcessor,\n\tResourceType,\n\ttype Secret,\n\ttype SnsTopic,\n\tSstEnvironmentBuilder,\n\ttype SstResource,\n\tsstResolvers,\n\ttype Vpc,\n} from './SstEnvironmentBuilder';\n\nexport {\n\tAWS_RUNTIME_ENV_VARS,\n\tCLOUDFLARE_RUNTIME_ENV_VARS,\n\tEnvValidationError,\n\tEnvValidator,\n\ttype EnvValidatorOptions,\n\tGCP_RUNTIME_ENV_VARS,\n\ttype LinkRecord,\n\tPLATFORM_ENV_VARS,\n\ttype Platform,\n\tplatformEnvVars,\n\tresolveEnvKeys,\n\ttype ValidationResult,\n} from './SstEnvValidator';\n\n// Import for deprecated function\nimport {\n\tSstEnvironmentBuilder,\n\ttype SstResource,\n} from './SstEnvironmentBuilder';\n\n/**\n * @deprecated Use `new SstEnvironmentBuilder(record).build()` instead.\n *\n * Normalizes SST resources and plain strings into environment variables.\n * Processes resources based on their type and converts names to environment case.\n *\n * @param record - Object containing resources and/or string values\n * @returns Normalized environment variables object\n *\n * @example\n * // Old usage (deprecated):\n * normalizeResourceEnv({ database: postgresResource })\n *\n * // New usage:\n * new SstEnvironmentBuilder({ database: postgresResource }).build()\n */\nexport function normalizeResourceEnv(\n\trecord: Record<string, SstResource | string>,\n): Record<string, string | number | boolean | Record<string, unknown>> {\n\treturn new SstEnvironmentBuilder(record).build();\n}\n\n// Keep Resource type as deprecated alias for backwards compatibility\n/**\n * @deprecated Use `SstResource` instead.\n */\nexport type Resource = SstResource;\n"],"mappings":";;;;;;AAaA,IAAY,eAAL,yBAAA,cAAA;CAEN,aAAA,kBAAA;CACA,aAAA,cAAA;CACA,aAAA,cAAA;CACA,aAAA,mBAAA;CACA,aAAA,SAAA;CACA,aAAA,YAAA;CACA,aAAA,YAAA;CACA,aAAA,WAAA;CAGA,aAAA,eAAA;CACA,aAAA,iBAAA;CACA,aAAA,qBAAA;CACA,aAAA,iBAAA;CACA,aAAA,sBAAA;CACA,aAAA,cAAA;CACA,aAAA,eAAA;CACA,aAAA,cAAA;CAKA,aAAA,gBAAA;CACA,aAAA,gBAAA;CAGA,aAAA,WAAA;CACA,aAAA,WAAA;;AACD,EAAA,CAAA,CAAA;AA0HA,MAAM,kBAAkB,MAAc,WAAwB,GAC5D,OAAO,MAAM,MACf;AAEA,MAAM,oBAAoB,KAAa,WAA0B;EAC/D,GAAG,IAAI,QAAQ,MAAM;EACrB,GAAG,IAAI,QAAQ,MAAM;EACrB,GAAG,IAAI,YAAY,MAAM;EACzB,GAAG,IAAI,QAAQ,MAAM;EACrB,GAAG,IAAI,YAAY,MAAM;EACzB,GAAG,IAAI,OAAO,gBAAgB,mBAAmB,MAAM,QAAQ,EAAE,GAAG,mBAAmB,MAAM,QAAQ,EAAE,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,GAAG,MAAM;AAC9I;AAEA,MAAM,kBAAkB,MAAc,WAAwB;EAC5D,GAAG,KAAK,QAAQ,MAAM;EAKtB,GAAG,KAAK,OAAO,MAAM,OAAO;AAC9B;AAEA,MAAM,iBAAiB,MAAc,WAA0B;EAC7D,GAAG,KAAK,OAAO,MAAM;EAGrB,GAAG,KAAK,6BAA6B,mBAAmB,mBAAmB,MAAM,GAAG;AACtF;AAEA,MAAM,iBAAiB,MAAc,WAAuB;EAC1D,GAAG,KAAK,OAAO,MAAM;EACrB,GAAG,KAAK,OAAO,MAAM;EAGrB,GAAG,KAAK,6BAA6B,mBAAmB,mBAAmB,MAAM,GAAG;AACtF;AAEA,MAAM,kBAAkB,MAAc,WAAwB,GAC5D,GAAG,KAAK,QAAQ,MAAM,KACxB;AAEA,MAAM,sBAAsB,CAAC;;;;AAK7B,MAAa,eAA0B;EAET,yBAAA;EACJ,qBAAA;EACL,gBAAA;EACG,mBAAA;EACE,qBAAA;EACK,mBAAA;EACP,mBAAA;EACD,kBAAA;EAGI,mBAAA;EACO,mBAAA;EACL,qBAAA;EACA,qBAAA;EACI,yBAAA;EACP,qBAAA;EACC,mBAAA;EACD,kBAAA;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFA,IAAa,wBAAb,MAEE;CACD;;;;;;;;CAYA,YACC,QACA,qBACA,SACC;EAED,MAAM,kBAA6B,sBAChC;GAAE,GAAG;GAAc,GAAG;EAAoB,IAC1C;EAEH,KAAK,UAAU,IAAI,mBAClB,QACA,iBACA,OACD;CACD;;;;;;CAOA,QAAmB;EAClB,OAAO,KAAK,QAAQ,MAAM;CAC3B;AACD;;;;;;;;AC5VA,MAAa,uBAAuB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;AAKA,MAAa,uBAAuB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;AAMA,MAAa,8BAA8B,CAC1C,YACA,cACD;;;;;AAMA,MAAa,oBAAoB;CAChC,KAAK;CACL,KAAK;CACL,YAAY;AACb;;;;;AAQA,SAAgB,gBAAgB,UAAuC;CACtE,OAAO,kBAAkB;AAC1B;;AAGA,MAAM,kBAAkB;;AAGxB,MAAM,uBAAuB;;;;AAwC7B,SAAS,YAAY,GAAW,GAAmB;CAClD,MAAM,IAAI,EAAE;CACZ,MAAM,IAAI,EAAE;CACZ,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,GAAG,OAAO;CAEpB,IAAI,OAAO,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;CAEpD,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC5B,MAAM,OAAiB,CAAC,CAAC;EACzB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;GAC5B,MAAM,OAAO,EAAE,IAAI,OAAO,EAAE,IAAI,KAAK,IAAI;GACzC,MAAM,OAAO,KAAK,MAAM,KAAK;GAC7B,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK;GACjC,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK;GACjC,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,GAAG;EACjC;EACA,OAAO;CACR;CAEA,OAAO,KAAK,MAAM;AACnB;;;;;;AAOA,SAAS,WAAW,GAAW,GAAmB;CACjD,MAAM,UAAU,IAAI,YAAY,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC;CAEtE,MAAM,KAAK,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC;CAC/C,MAAM,KAAK,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC;CAG/C,MAAM,WAFS,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,2BAClC,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,EAAA,CAAE,QAAQ;CAK9C,OAAO,KAAK,IAAI,SAAS,WAAW,IAAI;AACzC;;;;;AAMA,SAAS,eACR,SACA,WACA,MAAM,GACK;CACX,OAAO,UACL,KAAK,eAAe;EAAE;EAAW,OAAO,WAAW,SAAS,SAAS;CAAE,EAAE,CAAC,CAC1E,QAAQ,MAAM,EAAE,SAAS,oBAAoB,CAAC,CAC9C,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CACjC,MAAM,GAAG,GAAG,CAAC,CACb,KAAK,MAAM,EAAE,SAAS;AACzB;;;;;;AAOA,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAC7C,uBAAgC;CAChC;CACA;CACA;CACA;CAEA,YAAY,MAMT;EACF,MAAM,mBAAmB,OAAO,IAAI,CAAC;EACrC,KAAK,OAAO;EACZ,KAAK,UAAU,KAAK;EACpB,KAAK,YAAY,KAAK;EACtB,KAAK,cAAc,KAAK;EACxB,KAAK,UAAU,KAAK;EAEpB,MAIE,oBAAoB,MAAM,kBAAkB;CAC/C;CAEA,OAAe,OAAO,MAKX;EACV,MAAM,EAAE,SAAS,UAAU,aAAa,YAAY;EACpD,MAAM,MAAM,UAAU,IAAI,QAAQ,KAAK;EAEvC,MAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,KAAK,MAAM,EAAE,MAAM,CAAC;EACtD,MAAM,QAAQ,QAAQ,KAAK,MAAM;GAChC,MAAM,QAAQ,YAAY,MAAM,CAAC;GACjC,MAAM,OAAO,MAAM,SAAS,iBAAiB,MAAM,KAAK,MAAM,EAAE,MAAM;GACtE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,IAAI,OAAO,QAAQ;EAClD,CAAC;EAED,IAAI;EACJ,IAAI,SAAS,WAAW,GACvB,WAAW;OAOX,WAAW,sBALG,SAAS,MAAM,GAAG,eAAe,CAAC,CAAC,KAAK,IAKjB,IAHpC,SAAS,SAAS,kBACf,SAAS,SAAS,SAAS,gBAAgB,KAC3C;EAIL,OAAO,GAAG,IAAI,kCAAkC,MAAM,KAAK,IAAI,EAAE,MAAM;CACxE;AACD;;;;;;;;;;;;;;;;AAiBA,SAAgB,eAAe,QAA8B;CAC5D,MAAM,WAAuC,CAAC;CAC9C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC/C,SAAS,OAAO,OAAO,UAAU,WAAW,KAAK,EAAE,MAAM,MAAM,KAAK;CAErE,OAAO,OAAO,KAAK,IAAI,mBAAmB,UAAU,YAAY,CAAC,CAAC,MAAM,CAAC;AAC1E;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAb,MAA0B;;CAEzB;;CAEA;CACA;CACA;;CAEA;CAEA,YAAY,OAAmB,UAA+B,CAAC,GAAG;EACjE,MAAM,EAAE,UAAU,YAAY,CAAC,GAAG,YAAY;EAC9C,KAAK,UAAU;EACf,KAAK,iBAAiB,IAAI,IACzB,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAC5C,MACA,eAAe,GAAG,OAAO,MAAM,CAAC,CACjC,CAAC,CACF;EACA,KAAK,WAAW,CAAC,GAAG,KAAK,eAAe,OAAO,CAAC,CAAC,CAAC,KAAK;EACvD,KAAK,gBAAgB;GACpB,GAAG,KAAK;GACR,GAAI,WAAW,kBAAkB,YAAY,CAAC;GAC9C,GAAG;EACJ;EACA,KAAK,eAAe,IAAI,IAAI,KAAK,aAAa;CAC/C;;;;;;CAOA,uBAAuB,kBAA+C;EACrE,MAAM,YAAY,IAAI,IACrB,iBAAiB,KAAK,MAAO,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,CAAE,CACnE;EACA,MAAM,YAAsB,CAAC;EAC7B,KAAK,MAAM,CAAC,MAAM,SAAS,KAAK,gBAC/B,IAAI,KAAK,MAAM,MAAM,UAAU,IAAI,CAAC,CAAC,GAAG,UAAU,KAAK,IAAI;EAE5D,OAAO;CACR;;;;;;CAOA,SAAS,kBAAuD;EAC/D,MAAM,cAAc,iBAAiB,QAAQ,WAAW;GACvD,IAAI,OAAO,SAAS,GAAG,GAAG,OAAO;GACjC,OAAO,CAAC,KAAK,aAAa,IAAI,MAAM;EACrC,CAAC;EAED,MAAM,cAAwC,CAAC;EAC/C,KAAK,MAAM,UAAU,aAAa;GACjC,MAAM,UAAU,eAAe,QAAQ,KAAK,aAAa;GACzD,IAAI,QAAQ,QAAQ,YAAY,UAAU;EAC3C;EAEA,OAAO;GACN,OAAO,YAAY,WAAW;GAC9B;GACA,eAAe,KAAK;GACpB;EACD;CACD;;;;;;;CAQA,OAAO,kBAA2C;EACjD,MAAM,EAAE,OAAO,aAAa,gBAAgB,KAAK,SAAS,gBAAgB;EAE1E,IAAI,CAAC,OACJ,MAAM,IAAI,mBAAmB;GAC5B,SAAS;GACT,WAAW,KAAK;GAChB,UAAU,KAAK;GACf;GACA,SAAS,KAAK;EACf,CAAC;CAEH;;;;;CAMA,IAAI,QAAyB;EAC5B,OAAO,KAAK,aAAa,IAAI,MAAM;CACpC;AACD;;;;;;;;;;;;;;;;;;;AC/SA,SAAgB,qBACf,QACsE;CACtE,OAAO,IAAI,sBAAsB,MAAM,CAAC,CAAC,MAAM;AAChD"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentBuilder-15SdFJdK.cjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('api2') // 'API2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,8BAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentBuilder-C-2fViCT.mjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('api2') // 'API2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,UAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentBuilder-CoBQ9Xp2.d.mts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentBuilder-DeIle4QN.d.cts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentParser-BY1oCUsc.d.mts","names":[],"sources":["../src/EnvironmentParser.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;;;;AAS4B,cATf,YASe,CAAA,kBATgB,WAShB,CAAA,CAAA;EAAG,iBAMT,MAAA;EAAS,iBAArB,OAAA;EAAW;AA2FrB;;;;;EAiJmC,WAClB,CAAA,MAAA,EApPU,SAoPV,EAAA,OAAA,CAAA,EAnPW,GAmPX,CAAA,MAAA,CAAA;EAAU;;;AACX;EA6BJ,KAAA,CAAA,CAAA,EA3QF,WA2Qa,CA3QD,SA2QC,CAAA;EAAA;;;;;;;;;;;;;;;;EAKjB,uBAAC,CAAA,CAAA,EAAA,MAAA,EAAA;AAAC;AAWR;;;;AAEa;AAkBb;;;;;;;;;;;;;;cApNa,4BAA4B;;;;;;;;;;;sBAWH;;;;;;;;;;;;;;;;;;;;;;;;yBAsId,4BACP,eAAe,UAC5B,aAAa;;;;;;;;;;;;;;;;;;;;;;KA6BL,sBAAsB,6BACrB,IAAI,EAAE,WAAW,CAAA,CAAE,YAC5B,CAAA,CAAE,MAAM,EAAE,MACV,EAAE,WAAW,0BACZ,YAAY,EAAE,MACd,EAAE;;;;;;;;;KAWK,mDACL,iBACK;;;;;;;;;;;;;;KAkBA,WAAA,GAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentParser-Bzg5yXG2.cjs","names":["error: z.ZodError","options: FormatOptions","missingVars: Array<{ name: string; message: string }>","invalidVars: Array<{ name: string; value: unknown; message: string }>","lines: string[]","message: string","config: TResponse","envVars: Set<string>","errors: z.core.$ZodIssue[]","config: T","path: string[]","result: EmptyObject","z","schema: z.ZodType","name: string","issue: z.core.$ZodIssue","builder: (get: EnvFetcher) => TReturn"],"sources":["../src/formatter.ts","../src/EnvironmentParser.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\n/**\n * Options for formatting parse errors.\n */\nexport interface FormatOptions {\n\t/** Whether to use colors in output. Defaults to auto-detect TTY. */\n\tcolors?: boolean;\n}\n\n/**\n * ANSI color codes for terminal output.\n */\nconst colors = {\n\treset: '\\x1b[0m',\n\tred: '\\x1b[31m',\n\tyellow: '\\x1b[33m',\n\tcyan: '\\x1b[36m',\n\tdim: '\\x1b[2m',\n\tbold: '\\x1b[1m',\n};\n\n/**\n * Formats a ZodError into a user-friendly string for development.\n *\n * @param error - The ZodError to format\n * @param options - Formatting options\n * @returns Formatted error message\n *\n * @example\n * ```typescript\n * try {\n * config.parse();\n * } catch (error) {\n * if (error instanceof ZodError) {\n * console.error(formatParseError(error));\n * }\n * }\n * ```\n *\n * Output:\n * ```\n * Environment Configuration Failed\n *\n * Missing Variables:\n * DATABASE_URL - Required\n * JWT_SECRET - Required\n *\n * Invalid Values:\n * NODE_ENV = \"invalid\"\n * Expected: \"development\" | \"staging\" | \"production\"\n * ```\n */\nexport function formatParseError(\n\terror: z.ZodError,\n\toptions: FormatOptions = {},\n): string {\n\tconst useColors =\n\t\toptions.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);\n\n\tconst c = useColors\n\t\t? colors\n\t\t: { reset: '', red: '', yellow: '', cyan: '', dim: '', bold: '' };\n\n\tconst missingVars: Array<{ name: string; message: string }> = [];\n\tconst invalidVars: Array<{ name: string; value: unknown; message: string }> =\n\t\t[];\n\n\tfor (const issue of error.issues) {\n\t\t// Extract environment variable name from path or message\n\t\tlet envName = '';\n\t\tif (issue.path.length > 0) {\n\t\t\t// Join the full path with '.' to show nested config keys and env var name\n\t\t\tenvName = issue.path.map(String).join('.');\n\t\t} else {\n\t\t\t// Try to extract from message like 'Environment variable \"NAME\": ...'\n\t\t\tconst match = issue.message.match(/Environment variable \"([^\"]+)\"/);\n\t\t\tif (match?.[1]) {\n\t\t\t\tenvName = match[1];\n\t\t\t}\n\t\t}\n\n\t\t// Determine if this is a missing or invalid value\n\t\t// Use type guard for received property\n\t\tconst received = 'received' in issue ? issue.received : undefined;\n\t\tconst isMissing =\n\t\t\tissue.code === 'invalid_type' &&\n\t\t\t(received === 'undefined' || received === 'null');\n\n\t\tif (isMissing) {\n\t\t\tmissingVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t} else {\n\t\t\tinvalidVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tvalue: received,\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst lines: string[] = [];\n\n\tlines.push('');\n\tlines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);\n\tlines.push('');\n\n\tif (missingVars.length > 0) {\n\t\tlines.push(`${c.yellow}Missing Variables:${c.reset}`);\n\t\tfor (const v of missingVars) {\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\tif (invalidVars.length > 0) {\n\t\tlines.push(`${c.yellow}Invalid Values:${c.reset}`);\n\t\tfor (const v of invalidVars) {\n\t\t\tconst valueStr =\n\t\t\t\tv.value !== undefined ? ` = ${JSON.stringify(v.value)}` : '';\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);\n\t\t\tlines.push(` ${c.dim}${v.message}${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Cleans up a Zod error message by removing redundant prefixes.\n */\nfunction cleanMessage(message: string): string {\n\t// Remove \"Environment variable \"NAME\": \" prefix if present\n\treturn message.replace(/^Environment variable \"[^\"]+\": /, '');\n}\n\n/**\n * Checks if the current environment is development.\n */\nexport function isDevelopment(): boolean {\n\tconst nodeEnv = process.env.NODE_ENV?.toLowerCase();\n\treturn nodeEnv == null || nodeEnv === 'development' || nodeEnv === 'dev';\n}\n","import get from 'lodash.get';\nimport set from 'lodash.set';\nimport { z } from 'zod/v4';\nimport { formatParseError, isDevelopment } from './formatter.js';\n\n/**\n * Parses and validates configuration objects against Zod schemas.\n * Handles nested configurations and aggregates validation errors.\n *\n * @template TResponse - The shape of the configuration object\n */\nexport class ConfigParser<TResponse extends EmptyObject> {\n\t/**\n\t * Creates a new ConfigParser instance.\n\t *\n\t * @param config - The configuration object to parse\n\t * @param envVars - Set of environment variable names that were accessed\n\t */\n\tconstructor(\n\t\tprivate readonly config: TResponse,\n\t\tprivate readonly envVars: Set<string> = new Set(),\n\t) {}\n\t/**\n\t * Parses the config object and validates it against the Zod schemas\n\t * @returns The parsed config object\n\t */\n\tparse(): InferConfig<TResponse> {\n\t\tconst errors: z.core.$ZodIssue[] = [];\n\n\t\tconst parseDeep = <T>(config: T, path: string[] = []) => {\n\t\t\tconst result: EmptyObject = {};\n\n\t\t\tif (config && typeof config !== 'object') {\n\t\t\t\treturn config;\n\t\t\t}\n\n\t\t\tfor (const key in config) {\n\t\t\t\tconst schema = config[key];\n\t\t\t\tconst currentPath = [...path, key];\n\n\t\t\t\tif (schema instanceof z.ZodType) {\n\t\t\t\t\tconst parsed = schema.safeParse(undefined);\n\t\t\t\t\tif (parsed.success) {\n\t\t\t\t\t\tset(result, key, parsed.data);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the schema is invalid, assign the error\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t...parsed.error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\tpath: [...currentPath, ...(issue.path as string[])],\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (schema) {\n\t\t\t\t\tset(result, key, parseDeep(schema as EmptyObject, currentPath));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\n\t\tconst parsedConfig = parseDeep(\n\t\t\tthis.config,\n\t\t) as unknown as InferConfig<TResponse>;\n\n\t\tif (errors.length > 0) {\n\t\t\tconst zodError = new z.ZodError(errors);\n\t\t\t// In development, log a formatted error message before throwing\n\t\t\tif (isDevelopment()) {\n\t\t\t\tconsole.error(formatParseError(zodError));\n\t\t\t}\n\t\t\tthrow zodError;\n\t\t}\n\n\t\treturn parsedConfig;\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed during config creation.\n\t * This is useful for deployment and configuration management to know which env vars are required.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = envParser.create((get) => ({\n\t * dbUrl: get('DATABASE_URL').string(),\n\t * port: get('PORT').number()\n\t * }));\n\t *\n\t * config.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.envVars).sort();\n\t}\n}\n\n/**\n * Parses environment variables with type-safe validation using Zod schemas.\n * Provides a fluent API for defining environment variable schemas with automatic\n * error context enrichment.\n *\n * @template T - The type of the configuration object (typically process.env)\n *\n * @example\n * ```typescript\n * const config = new EnvironmentParser(process.env)\n * .create((get) => ({\n * port: get('PORT').string().transform(Number).default(3000),\n * database: {\n * url: get('DATABASE_URL').string().url()\n * }\n * }))\n * .parse();\n * ```\n */\nexport class EnvironmentParser<T extends EmptyObject> {\n\t/**\n\t * Set to track which environment variable names have been accessed\n\t */\n\tprivate readonly accessedVars: Set<string> = new Set();\n\n\t/**\n\t * Creates a new EnvironmentParser instance.\n\t *\n\t * @param config - The configuration object to parse (typically process.env)\n\t */\n\tconstructor(private readonly config: T) {}\n\n\t/**\n\t * Wraps a Zod schema to intercept parse/safeParse calls and enrich error messages\n\t * with environment variable context.\n\t *\n\t * @param schema - The Zod schema to wrap\n\t * @param name - The environment variable name for error context\n\t * @returns A wrapped Zod schema with enhanced error reporting\n\t */\n\tprivate wrapSchema = (schema: z.ZodType, name: string): z.ZodType => {\n\t\t// Create a proxy that intercepts all method calls on the schema\n\t\treturn new Proxy(schema, {\n\t\t\tget: (target, prop) => {\n\t\t\t\tif (prop === 'parse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn target.parse(value);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\t\tconst modifiedIssues = error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\t\tthrow new z.ZodError(modifiedIssues);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (prop === 'safeParse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\tconst result = target.safeParse(value);\n\n\t\t\t\t\t\tif (!result.success) {\n\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\tconst modifiedIssues = result.error.issues.map(\n\t\t\t\t\t\t\t\t(issue: z.core.$ZodIssue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tsuccess: false as const,\n\t\t\t\t\t\t\t\terror: new z.ZodError(modifiedIssues),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// For any method that returns a new schema (like transform, optional, etc.),\n\t\t\t\t// wrap the result as well\n\t\t\t\tconst originalProp = target[prop as keyof typeof target];\n\t\t\t\tif (typeof originalProp === 'function') {\n\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\tconst result = originalProp.apply(target, args);\n\t\t\t\t\t\t// If the result is a ZodType, wrap it too\n\t\t\t\t\t\tif (result && typeof result === 'object' && 'parse' in result) {\n\t\t\t\t\t\t\treturn this.wrapSchema(result, name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn originalProp;\n\t\t\t},\n\t\t});\n\t};\n\n\t/**\n\t * Creates a proxied version of the Zod object that wraps all schema creators\n\t * to provide enhanced error messages with environment variable context.\n\t *\n\t * @param name - The environment variable name\n\t * @returns A proxied Zod object with wrapped schema creators\n\t */\n\tprivate getZodGetter = (name: string) => {\n\t\t// Track that this environment variable was accessed\n\t\tthis.accessedVars.add(name);\n\n\t\t// Return an object that has all Zod schemas but with our wrapper\n\t\treturn new Proxy(\n\t\t\t{ ...z },\n\t\t\t{\n\t\t\t\tget: (target, prop) => {\n\t\t\t\t\t// deno-lint-ignore ban-ts-comment\n\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\tconst value = target[prop];\n\n\t\t\t\t\tif (typeof value === 'function') {\n\t\t\t\t\t\t// Return a wrapper around each Zod schema creator\n\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\tconst schema = value(...args);\n\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Handle objects like z.coerce\n\t\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\t\treturn new Proxy(value, {\n\t\t\t\t\t\t\tget: (nestedTarget, nestedProp) => {\n\t\t\t\t\t\t\t\tconst nestedValue =\n\t\t\t\t\t\t\t\t\tnestedTarget[nestedProp as keyof typeof nestedTarget];\n\t\t\t\t\t\t\t\tif (typeof nestedValue === 'function') {\n\t\t\t\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\t\t\t\tconst schema = nestedValue(...args);\n\t\t\t\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn nestedValue;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn value;\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t};\n\n\t/**\n\t * Creates a new ConfigParser object that can be used to parse the config object\n\t *\n\t * @param builder - A function that takes a getter function and returns a config object\n\t * @returns A ConfigParser object that can be used to parse the config object\n\t */\n\tcreate<TReturn extends EmptyObject>(\n\t\tbuilder: (get: EnvFetcher) => TReturn,\n\t): ConfigParser<TReturn> {\n\t\tconst config = builder(this.getZodGetter);\n\t\treturn new ConfigParser(config, this.accessedVars);\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed via the getter.\n\t * This is useful for build-time analysis to determine which env vars a service needs.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const sniffer = new EnvironmentParser({});\n\t * service.register(sniffer);\n\t * const envVars = sniffer.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.accessedVars).sort();\n\t}\n}\n\n/**\n * Infers the TypeScript type of a configuration object based on its Zod schemas.\n * Recursively processes nested objects and extracts types from Zod schemas.\n *\n * @template T - The configuration object type\n */\nexport type InferConfig<T extends EmptyObject> = {\n\t[K in keyof T]: T[K] extends z.ZodSchema\n\t\t? z.infer<T[K]>\n\t\t: T[K] extends Record<string, unknown>\n\t\t\t? InferConfig<T[K]>\n\t\t\t: T[K];\n};\n\n/**\n * Function type for fetching environment variables with Zod validation.\n * Returns a Zod object scoped to a specific environment variable.\n *\n * @template TPath - The environment variable path type\n * @param name - The environment variable name\n * @returns A Zod object for defining the schema\n */\nexport type EnvFetcher<TPath extends string = string> = (\n\tname: TPath,\n) => typeof z;\n\n/**\n * Function type for building environment configuration objects.\n * Takes an EnvFetcher and returns a configuration object with Zod schemas.\n *\n * @template TResponse - The response configuration object type\n * @param get - The environment variable fetcher function\n * @returns The configuration object with Zod schemas\n */\nexport type EnvironmentBuilder<TResponse extends EmptyObject> = (\n\tget: EnvFetcher,\n) => TResponse;\n\n/**\n * Type alias for a generic object with unknown values.\n * Used as a constraint for configuration objects.\n */\nexport type EmptyObject = Record<string | number | symbol, unknown>;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentParser-DoooZm8n.d.cts","names":[],"sources":["../src/EnvironmentParser.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;;;;AAS4B,cATf,YASe,CAAA,kBATgB,WAShB,CAAA,CAAA;EAAG,iBAMT,MAAA;EAAS,iBAArB,OAAA;EAAW;AA2FrB;;;;;EAiJmC,WAClB,CAAA,MAAA,EApPU,SAoPV,EAAA,OAAA,CAAA,EAnPW,GAmPX,CAAA,MAAA,CAAA;EAAU;;;AACX;EA6BJ,KAAA,CAAA,CAAA,EA3QF,WA2Qa,CA3QD,SA2QC,CAAA;EAAA;;;;;;;;;;;;;;;;EAKjB,uBAAC,CAAA,CAAA,EAAA,MAAA,EAAA;AAAC;AAWR;;;;AAEa;AAkBb;;;;;;;;;;;;;;cApNa,4BAA4B;;;;;;;;;;;sBAWH;;;;;;;;;;;;;;;;;;;;;;;;yBAsId,4BACP,eAAe,UAC5B,aAAa;;;;;;;;;;;;;;;;;;;;;;KA6BL,sBAAsB,6BACrB,IAAI,EAAE,WAAW,CAAA,CAAE,YAC5B,CAAA,CAAE,MAAM,EAAE,MACV,EAAE,WAAW,0BACZ,YAAY,EAAE,MACd,EAAE;;;;;;;;;KAWK,mDACL,iBACK;;;;;;;;;;;;;;KAkBA,WAAA,GAAc"}
|