@geekmidas/envkit 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/{EnvironmentBuilder-DfmYRBm-.mjs → EnvironmentBuilder-BSuHZm0y.mjs} +2 -4
  2. package/dist/EnvironmentBuilder-BSuHZm0y.mjs.map +1 -0
  3. package/dist/EnvironmentBuilder-DHfDXJUm.d.mts.map +1 -0
  4. package/dist/{EnvironmentBuilder-W2wku49g.cjs → EnvironmentBuilder-Djr1VsWM.cjs} +2 -4
  5. package/dist/EnvironmentBuilder-Djr1VsWM.cjs.map +1 -0
  6. package/dist/EnvironmentBuilder-Xuf2Dd9u.d.cts.map +1 -0
  7. package/dist/EnvironmentBuilder.cjs +1 -1
  8. package/dist/EnvironmentBuilder.mjs +1 -1
  9. package/dist/EnvironmentParser-Bt246UeP.cjs.map +1 -1
  10. package/dist/{EnvironmentParser-CVWU1ooT.d.mts → EnvironmentParser-CY8TosTN.d.mts} +2 -1
  11. package/dist/EnvironmentParser-CY8TosTN.d.mts.map +1 -0
  12. package/dist/{EnvironmentParser-tV-JjCg7.d.cts → EnvironmentParser-DtOL86NU.d.cts} +2 -1
  13. package/dist/EnvironmentParser-DtOL86NU.d.cts.map +1 -0
  14. package/dist/EnvironmentParser-c06agx31.mjs.map +1 -1
  15. package/dist/EnvironmentParser.d.cts +1 -1
  16. package/dist/EnvironmentParser.d.mts +1 -1
  17. package/dist/SnifferEnvironmentParser.cjs.map +1 -1
  18. package/dist/SnifferEnvironmentParser.d.cts +3 -2
  19. package/dist/SnifferEnvironmentParser.d.cts.map +1 -0
  20. package/dist/SnifferEnvironmentParser.d.mts +3 -2
  21. package/dist/SnifferEnvironmentParser.d.mts.map +1 -0
  22. package/dist/SnifferEnvironmentParser.mjs.map +1 -1
  23. package/dist/{SstEnvironmentBuilder-DEa3lTUB.mjs → SstEnvironmentBuilder-BEBFSUYr.mjs} +2 -2
  24. package/dist/SstEnvironmentBuilder-BEBFSUYr.mjs.map +1 -0
  25. package/dist/SstEnvironmentBuilder-CjURMGjW.d.mts.map +1 -0
  26. package/dist/SstEnvironmentBuilder-D4oSo_KX.d.cts.map +1 -0
  27. package/dist/{SstEnvironmentBuilder-BuFw1hCe.cjs → SstEnvironmentBuilder-wFnN2M5O.cjs} +2 -2
  28. package/dist/SstEnvironmentBuilder-wFnN2M5O.cjs.map +1 -0
  29. package/dist/SstEnvironmentBuilder.cjs +2 -2
  30. package/dist/SstEnvironmentBuilder.mjs +2 -2
  31. package/dist/credentials.cjs +66 -0
  32. package/dist/credentials.cjs.map +1 -0
  33. package/dist/credentials.d.cts +31 -0
  34. package/dist/credentials.d.cts.map +1 -0
  35. package/dist/credentials.d.mts +31 -0
  36. package/dist/credentials.d.mts.map +1 -0
  37. package/dist/credentials.mjs +62 -0
  38. package/dist/credentials.mjs.map +1 -0
  39. package/dist/index.cjs +1 -1
  40. package/dist/index.d.cts +1 -1
  41. package/dist/index.d.mts +1 -1
  42. package/dist/index.mjs +1 -1
  43. package/dist/sst.cjs +2 -2
  44. package/dist/sst.cjs.map +1 -1
  45. package/dist/sst.d.cts +1 -0
  46. package/dist/sst.d.cts.map +1 -0
  47. package/dist/sst.d.mts +1 -0
  48. package/dist/sst.d.mts.map +1 -0
  49. package/dist/sst.mjs +2 -2
  50. package/dist/sst.mjs.map +1 -1
  51. package/examples/basic-usage.ts +329 -333
  52. package/package.json +6 -1
  53. package/src/EnvironmentBuilder.ts +76 -80
  54. package/src/EnvironmentParser.ts +231 -231
  55. package/src/SnifferEnvironmentParser.ts +178 -178
  56. package/src/SstEnvironmentBuilder.ts +127 -127
  57. package/src/__tests__/ConfigParser.spec.ts +388 -388
  58. package/src/__tests__/EnvironmentBuilder.spec.ts +245 -265
  59. package/src/__tests__/EnvironmentParser.spec.ts +828 -828
  60. package/src/__tests__/SnifferEnvironmentParser.spec.ts +380 -326
  61. package/src/__tests__/SstEnvironmentBuilder.spec.ts +347 -367
  62. package/src/__tests__/credentials.integration.spec.ts +239 -0
  63. package/src/__tests__/credentials.spec.ts +136 -0
  64. package/src/__tests__/sst.spec.ts +390 -413
  65. package/src/credentials.ts +99 -0
  66. package/src/index.ts +11 -11
  67. package/src/sst.ts +24 -24
  68. package/sst-env.d.ts +0 -1
  69. package/tsconfig.json +9 -0
  70. package/dist/EnvironmentBuilder-DfmYRBm-.mjs.map +0 -1
  71. package/dist/EnvironmentBuilder-W2wku49g.cjs.map +0 -1
  72. package/dist/SstEnvironmentBuilder-BuFw1hCe.cjs.map +0 -1
  73. package/dist/SstEnvironmentBuilder-DEa3lTUB.mjs.map +0 -1
@@ -0,0 +1,99 @@
1
+ import { createDecipheriv } from 'node:crypto';
2
+
3
+ /**
4
+ * Build-time injected encrypted credentials.
5
+ * These are replaced by tsdown/esbuild --define at build time.
6
+ */
7
+ declare const __GKM_ENCRYPTED_CREDENTIALS__: string | undefined;
8
+ declare const __GKM_CREDENTIALS_IV__: string | undefined;
9
+
10
+ /** AES-256-GCM auth tag length */
11
+ const AUTH_TAG_LENGTH = 16;
12
+
13
+ /**
14
+ * Decrypt credentials from encrypted payload.
15
+ * Exported for testing purposes.
16
+ */
17
+ export function decryptCredentials(
18
+ encrypted: string,
19
+ iv: string,
20
+ masterKey: string,
21
+ ): Record<string, string> {
22
+ const key = Buffer.from(masterKey, 'hex');
23
+ const ivBuffer = Buffer.from(iv, 'hex');
24
+ const combined = Buffer.from(encrypted, 'base64');
25
+
26
+ // Split ciphertext and auth tag
27
+ const ciphertext = combined.subarray(0, -AUTH_TAG_LENGTH);
28
+ const authTag = combined.subarray(-AUTH_TAG_LENGTH);
29
+
30
+ // Decrypt using AES-256-GCM
31
+ const decipher = createDecipheriv('aes-256-gcm', key, ivBuffer);
32
+ decipher.setAuthTag(authTag);
33
+
34
+ const plaintext = Buffer.concat([
35
+ decipher.update(ciphertext),
36
+ decipher.final(),
37
+ ]);
38
+
39
+ return JSON.parse(plaintext.toString('utf-8'));
40
+ }
41
+
42
+ /**
43
+ * Credentials object for use with EnvironmentParser.
44
+ *
45
+ * In development mode (no embedded credentials), this returns an empty object.
46
+ * In production mode, it decrypts embedded credentials using the GKM_MASTER_KEY
47
+ * environment variable.
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { EnvironmentParser } from '@geekmidas/envkit';
52
+ * import { Credentials } from '@geekmidas/envkit/credentials';
53
+ *
54
+ * export const envParser = new EnvironmentParser({...process.env, ...Credentials})
55
+ * .create((get) => ({
56
+ * database: {
57
+ * url: get('DATABASE_URL').string(),
58
+ * },
59
+ * }))
60
+ * .parse();
61
+ * ```
62
+ */
63
+ export const Credentials: Record<string, string> = (() => {
64
+ // Development mode - no credentials embedded at build time
65
+ if (
66
+ typeof __GKM_ENCRYPTED_CREDENTIALS__ === 'undefined' ||
67
+ typeof __GKM_CREDENTIALS_IV__ === 'undefined'
68
+ ) {
69
+ return {};
70
+ }
71
+
72
+ // Production mode - decrypt credentials using master key
73
+ const masterKey = process.env.GKM_MASTER_KEY;
74
+
75
+ if (!masterKey) {
76
+ // Log warning but don't throw - allows graceful fallback to env vars
77
+ console.error(
78
+ '[gkm] GKM_MASTER_KEY environment variable is required to decrypt credentials.',
79
+ );
80
+ console.error(
81
+ '[gkm] Falling back to environment variables. Some secrets may be missing.',
82
+ );
83
+ return {};
84
+ }
85
+
86
+ try {
87
+ return decryptCredentials(
88
+ __GKM_ENCRYPTED_CREDENTIALS__,
89
+ __GKM_CREDENTIALS_IV__,
90
+ masterKey,
91
+ );
92
+ } catch (error) {
93
+ console.error('[gkm] Failed to decrypt credentials:', error);
94
+ console.error('[gkm] Falling back to environment variables.');
95
+ return {};
96
+ }
97
+ })();
98
+
99
+ export default Credentials;
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
- export { EnvironmentParser, ConfigParser } from './EnvironmentParser';
2
1
  export {
3
- EnvironmentBuilder,
4
- environmentCase,
5
- type EnvRecord,
6
- type EnvValue,
7
- type EnvironmentResolver,
8
- type Resolvers,
9
- type EnvironmentBuilderOptions,
10
- type InputValue,
11
- type TypedInputValue,
12
- type TypedResolvers,
2
+ EnvironmentBuilder,
3
+ type EnvironmentBuilderOptions,
4
+ type EnvironmentResolver,
5
+ type EnvRecord,
6
+ type EnvValue,
7
+ environmentCase,
8
+ type InputValue,
9
+ type Resolvers,
10
+ type TypedInputValue,
11
+ type TypedResolvers,
13
12
  } from './EnvironmentBuilder';
13
+ export { ConfigParser, EnvironmentParser } from './EnvironmentParser';
package/src/sst.ts CHANGED
@@ -1,33 +1,33 @@
1
1
  // Re-export everything from SstEnvironmentBuilder
2
- export {
3
- SstEnvironmentBuilder,
4
- sstResolvers,
5
- ResourceType,
6
- type ApiGatewayV2,
7
- type Postgres,
8
- type Function,
9
- type Bucket,
10
- type Vpc,
11
- type Secret,
12
- type SnsTopic,
13
- type SstResource,
14
- type ResourceProcessor,
15
- } from './SstEnvironmentBuilder';
16
-
17
- // Re-export environmentCase from EnvironmentBuilder
18
- export { environmentCase } from './EnvironmentBuilder';
19
2
 
20
3
  // Re-export types from EnvironmentBuilder
21
4
  export type {
22
- EnvRecord,
23
- EnvValue,
24
- EnvironmentBuilderOptions,
5
+ EnvironmentBuilderOptions,
6
+ EnvRecord,
7
+ EnvValue,
25
8
  } from './EnvironmentBuilder';
26
9
 
10
+ // Re-export environmentCase from EnvironmentBuilder
11
+ export { environmentCase } from './EnvironmentBuilder';
12
+ export {
13
+ type ApiGatewayV2,
14
+ type Bucket,
15
+ type Function,
16
+ type Postgres,
17
+ type ResourceProcessor,
18
+ ResourceType,
19
+ type Secret,
20
+ type SnsTopic,
21
+ SstEnvironmentBuilder,
22
+ type SstResource,
23
+ sstResolvers,
24
+ type Vpc,
25
+ } from './SstEnvironmentBuilder';
26
+
27
27
  // Import for deprecated function
28
28
  import {
29
- SstEnvironmentBuilder,
30
- type SstResource,
29
+ SstEnvironmentBuilder,
30
+ type SstResource,
31
31
  } from './SstEnvironmentBuilder';
32
32
 
33
33
  /**
@@ -47,9 +47,9 @@ import {
47
47
  * new SstEnvironmentBuilder({ database: postgresResource }).build()
48
48
  */
49
49
  export function normalizeResourceEnv(
50
- record: Record<string, SstResource | string>,
50
+ record: Record<string, SstResource | string>,
51
51
  ): Record<string, string | number | boolean | Record<string, unknown>> {
52
- return new SstEnvironmentBuilder(record).build();
52
+ return new SstEnvironmentBuilder(record).build();
53
53
  }
54
54
 
55
55
  // Keep Resource type as deprecated alias for backwards compatibility
package/sst-env.d.ts CHANGED
@@ -6,4 +6,3 @@
6
6
  /// <reference path="../../sst-env.d.ts" />
7
7
 
8
8
  import 'sst';
9
- export {};
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"]
9
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"EnvironmentBuilder-DfmYRBm-.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('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n return snakecase(name)\n .toUpperCase()\n .replace(/_\\d+/g, (r) => {\n return r.replace('_', '');\n });\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 [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 /**\n * Handler called when a value's type doesn't match any registered resolver.\n * Defaults to console.warn.\n */\n onUnmatchedValue?: (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 type: TType;\n [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 [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 TRecord extends Record<string, InputValue>,\n TType extends string,\n> = {\n [K in keyof TRecord]: TRecord[K] extends { type: TType }\n ? OmitType<TRecord[K]>\n : 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 [TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n ValueForType<TRecord, TType>\n >;\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 TRecord extends Record<string, InputValue> = Record<string, InputValue>,\n TResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n private readonly record: TRecord;\n private readonly resolvers: TResolvers;\n private readonly options: Required<EnvironmentBuilderOptions>;\n\n constructor(\n record: TRecord,\n resolvers: TResolvers,\n options: EnvironmentBuilderOptions = {},\n ) {\n this.record = record;\n this.resolvers = resolvers;\n this.options = {\n onUnmatchedValue:\n options.onUnmatchedValue ??\n ((key, value) => {\n console.warn(`No resolver found for key \"${key}\":`, { value });\n }),\n };\n }\n\n /**\n * Build environment variables from the input record.\n *\n * - Plain string values are passed through with key transformation\n * - Object values with a `type` property are matched against resolvers\n * - Resolvers receive values without the `type` key\n * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n *\n * @returns A record of environment variables\n */\n build(): EnvRecord {\n const env: EnvRecord = {};\n\n for (const [key, value] of Object.entries(this.record)) {\n // Handle plain string values\n if (typeof value === 'string') {\n env[environmentCase(key)] = value;\n continue;\n }\n\n // Handle objects with type discriminator\n const { type, ...rest } = value;\n const resolver = this.resolvers[type];\n if (resolver) {\n const resolved = resolver(key, rest);\n // Transform only root-level keys from resolver output\n for (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n env[environmentCase(resolvedKey)] = resolvedValue;\n }\n } else {\n this.options.onUnmatchedValue(key, value);\n }\n }\n\n return env;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACpD,QAAO,UAAU,KAAK,CACnB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACvB,SAAO,EAAE,QAAQ,KAAK,GAAG;CAC1B,EAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACA,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACEC,QACAC,WACAC,UAAqC,CAAE,GACvC;AACA,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACb,kBACE,QAAQ,qBACP,CAAC,KAAK,UAAU;AACf,WAAQ,MAAM,6BAA6B,IAAI,KAAK,EAAE,MAAO,EAAC;EAC/D,GACJ;CACF;;;;;;;;;;;CAYD,QAAmB;EACjB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEtD,cAAW,UAAU,UAAU;AAC7B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACD;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACZ,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CACjE,KAAI,gBAAgB,YAAY,IAAI;GAEvC,MACC,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE5C;AAED,SAAO;CACR;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EnvironmentBuilder-W2wku49g.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('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n return snakecase(name)\n .toUpperCase()\n .replace(/_\\d+/g, (r) => {\n return r.replace('_', '');\n });\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 [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 /**\n * Handler called when a value's type doesn't match any registered resolver.\n * Defaults to console.warn.\n */\n onUnmatchedValue?: (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 type: TType;\n [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 [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 TRecord extends Record<string, InputValue>,\n TType extends string,\n> = {\n [K in keyof TRecord]: TRecord[K] extends { type: TType }\n ? OmitType<TRecord[K]>\n : 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 [TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n ValueForType<TRecord, TType>\n >;\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 TRecord extends Record<string, InputValue> = Record<string, InputValue>,\n TResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n private readonly record: TRecord;\n private readonly resolvers: TResolvers;\n private readonly options: Required<EnvironmentBuilderOptions>;\n\n constructor(\n record: TRecord,\n resolvers: TResolvers,\n options: EnvironmentBuilderOptions = {},\n ) {\n this.record = record;\n this.resolvers = resolvers;\n this.options = {\n onUnmatchedValue:\n options.onUnmatchedValue ??\n ((key, value) => {\n console.warn(`No resolver found for key \"${key}\":`, { value });\n }),\n };\n }\n\n /**\n * Build environment variables from the input record.\n *\n * - Plain string values are passed through with key transformation\n * - Object values with a `type` property are matched against resolvers\n * - Resolvers receive values without the `type` key\n * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n *\n * @returns A record of environment variables\n */\n build(): EnvRecord {\n const env: EnvRecord = {};\n\n for (const [key, value] of Object.entries(this.record)) {\n // Handle plain string values\n if (typeof value === 'string') {\n env[environmentCase(key)] = value;\n continue;\n }\n\n // Handle objects with type discriminator\n const { type, ...rest } = value;\n const resolver = this.resolvers[type];\n if (resolver) {\n const resolved = resolver(key, rest);\n // Transform only root-level keys from resolver output\n for (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n env[environmentCase(resolvedKey)] = resolvedValue;\n }\n } else {\n this.options.onUnmatchedValue(key, value);\n }\n }\n\n return env;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACpD,QAAO,8BAAU,KAAK,CACnB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACvB,SAAO,EAAE,QAAQ,KAAK,GAAG;CAC1B,EAAC;AACL;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACA,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACEC,QACAC,WACAC,UAAqC,CAAE,GACvC;AACA,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACb,kBACE,QAAQ,qBACP,CAAC,KAAK,UAAU;AACf,WAAQ,MAAM,6BAA6B,IAAI,KAAK,EAAE,MAAO,EAAC;EAC/D,GACJ;CACF;;;;;;;;;;;CAYD,QAAmB;EACjB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEtD,cAAW,UAAU,UAAU;AAC7B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACD;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACZ,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CACjE,KAAI,gBAAgB,YAAY,IAAI;GAEvC,MACC,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE5C;AAED,SAAO;CACR;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SstEnvironmentBuilder-BuFw1hCe.cjs","names":["name: string","value: SecretValue","key: string","value: PostgresValue","value: BucketValue","value: SnsTopicValue","sstResolvers: Resolvers","record: TRecord","additionalResolvers?: CustomResolvers<TRecord>","options?: EnvironmentBuilderOptions","mergedResolvers: Resolvers","EnvironmentBuilder"],"sources":["../src/SstEnvironmentBuilder.ts"],"sourcesContent":["import {\n type EnvRecord,\n EnvironmentBuilder,\n type EnvironmentBuilderOptions,\n type EnvironmentResolver,\n type InputValue,\n type 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 // Legacy format (dot notation)\n ApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n Postgres = 'sst.aws.Postgres',\n Function = 'sst.aws.Function',\n Bucket = 'sst.aws.Bucket',\n Vpc = 'sst.aws.Vpc',\n Secret = 'sst.sst.Secret',\n\n // Modern format (colon notation)\n SSTSecret = 'sst:sst:Secret',\n SSTFunction = 'sst:sst:Function',\n SSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n SSTPostgres = 'sst:aws:Postgres',\n SSTBucket = 'sst:aws:Bucket',\n SnsTopic = 'sst:aws:SnsTopic',\n}\n\n/**\n * AWS API Gateway V2 resource type.\n * Represents an HTTP/WebSocket API.\n */\nexport type ApiGatewayV2 = {\n type: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n url: 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 type: ResourceType.Postgres | ResourceType.SSTPostgres;\n database: string;\n host: string;\n password: string;\n port: number;\n username: string;\n};\n\n/**\n * AWS Lambda Function resource type.\n */\nexport type Function = {\n type: ResourceType.Function | ResourceType.SSTFunction;\n name: string;\n};\n\n/**\n * AWS S3 Bucket resource type.\n */\nexport type Bucket = {\n type: ResourceType.Bucket | ResourceType.SSTBucket;\n name: string;\n};\n\n/**\n * AWS VPC (Virtual Private Cloud) resource type.\n */\nexport type Vpc = {\n type: ResourceType.Vpc;\n bastion: string;\n};\n\n/**\n * Secret resource type for storing sensitive values.\n */\nexport type Secret = {\n type: ResourceType.Secret | ResourceType.SSTSecret;\n value: string;\n};\n\n/**\n * AWS SNS Topic resource type.\n */\nexport type SnsTopic = {\n type: ResourceType.SnsTopic;\n arn: string;\n};\n\n/**\n * Union type of all supported SST resource types.\n */\nexport type SstResource =\n | ApiGatewayV2\n | Postgres\n | Function\n | Bucket\n | Vpc\n | Secret\n | SnsTopic;\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'>;\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 [name]: value.value,\n});\n\nconst postgresResolver = (key: string, value: PostgresValue) => ({\n [`${key}Name`]: value.database,\n [`${key}Host`]: value.host,\n [`${key}Password`]: value.password,\n [`${key}Port`]: value.port,\n [`${key}Username`]: value.username,\n});\n\nconst bucketResolver = (name: string, value: BucketValue) => ({\n [`${name}Name`]: value.name,\n});\n\nconst topicResolver = (name: string, value: SnsTopicValue) => ({\n [`${name}Arn`]: value.arn,\n});\n\nconst noopResolver = () => ({});\n\n/**\n * Pre-configured resolvers for all SST resource types.\n */\nexport const sstResolvers: Resolvers = {\n // Legacy format\n [ResourceType.ApiGatewayV2]: noopResolver,\n [ResourceType.Function]: noopResolver,\n [ResourceType.Vpc]: noopResolver,\n [ResourceType.Secret]: secretResolver,\n [ResourceType.Postgres]: postgresResolver,\n [ResourceType.Bucket]: bucketResolver,\n\n // Modern format\n [ResourceType.SSTSecret]: secretResolver,\n [ResourceType.SSTBucket]: bucketResolver,\n [ResourceType.SSTFunction]: noopResolver,\n [ResourceType.SSTPostgres]: postgresResolver,\n [ResourceType.SSTApiGatewayV2]: noopResolver,\n [ResourceType.SnsTopic]: topicResolver,\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 [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 AllTypeValues<TRecord>,\n SstResourceTypeString\n>;\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n TRecord extends Record<string, InputValue>,\n TType extends string,\n> = {\n [K in keyof TRecord]: TRecord[K] extends { type: TType }\n ? OmitType<TRecord[K]>\n : 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 CustomTypeValues<TRecord> extends never\n ? Resolvers | undefined\n : {\n [TType in CustomTypeValues<TRecord>]: EnvironmentResolver<\n ValueForType<TRecord, TType>\n >;\n };\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 TRecord extends Record<string, SstResource | InputValue | string>,\n> {\n private readonly builder: EnvironmentBuilder<\n Record<string, InputValue>,\n Resolvers\n >;\n\n /**\n * Create a new SST environment builder.\n *\n * @param record - Object containing SST resources, custom resources, and/or string values\n * @param additionalResolvers - Optional custom resolvers (typed based on custom types in record)\n * @param options - Optional configuration options\n */\n constructor(\n record: TRecord,\n additionalResolvers?: CustomResolvers<TRecord>,\n options?: EnvironmentBuilderOptions,\n ) {\n // Merge resolvers with custom ones taking precedence\n const mergedResolvers: Resolvers = additionalResolvers\n ? { ...sstResolvers, ...additionalResolvers }\n : sstResolvers;\n\n this.builder = new EnvironmentBuilder(\n record as Record<string, InputValue>,\n mergedResolvers,\n options,\n );\n }\n\n /**\n * Build environment variables from the input record.\n *\n * @returns A record of environment variables\n */\n build(): EnvRecord {\n return this.builder.build();\n }\n}\n\n// Re-export useful types\nexport { environmentCase } from './EnvironmentBuilder';\nexport type {\n EnvRecord,\n EnvValue,\n EnvironmentBuilderOptions,\n} from './EnvironmentBuilder';\n"],"mappings":";;;;;;;AAaA,IAAY,wDAAL;AAEL;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;;AACD;AA8FD,MAAM,iBAAiB,CAACA,MAAcC,WAAwB,GAC3D,OAAO,MAAM,MACf;AAED,MAAM,mBAAmB,CAACC,KAAaC,WAA0B;GAC7D,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,YAAY,MAAM;GACxB,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,YAAY,MAAM;AAC3B;AAED,MAAM,iBAAiB,CAACH,MAAcI,WAAwB,IAC1D,EAAE,KAAK,QAAQ,MAAM,KACxB;AAED,MAAM,gBAAgB,CAACJ,MAAcK,WAA0B,IAC3D,EAAE,KAAK,OAAO,MAAM,IACvB;AAED,MAAM,eAAe,OAAO,CAAE;;;;AAK9B,MAAaC,eAA0B;EAEpC,aAAa,eAAe;EAC5B,aAAa,WAAW;EACxB,aAAa,MAAM;EACnB,aAAa,SAAS;EACtB,aAAa,WAAW;EACxB,aAAa,SAAS;EAGtB,aAAa,YAAY;EACzB,aAAa,YAAY;EACzB,aAAa,cAAc;EAC3B,aAAa,cAAc;EAC3B,aAAa,kBAAkB;EAC/B,aAAa,WAAW;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFD,IAAa,wBAAb,MAEE;CACA,AAAiB;;;;;;;;CAYjB,YACEC,QACAC,qBACAC,SACA;EAEA,MAAMC,kBAA6B,sBAC/B;GAAE,GAAG;GAAc,GAAG;EAAqB,IAC3C;AAEJ,OAAK,UAAU,IAAIC,8CACjB,QACA,iBACA;CAEH;;;;;;CAOD,QAAmB;AACjB,SAAO,KAAK,QAAQ,OAAO;CAC5B;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SstEnvironmentBuilder-DEa3lTUB.mjs","names":["name: string","value: SecretValue","key: string","value: PostgresValue","value: BucketValue","value: SnsTopicValue","sstResolvers: Resolvers","record: TRecord","additionalResolvers?: CustomResolvers<TRecord>","options?: EnvironmentBuilderOptions","mergedResolvers: Resolvers"],"sources":["../src/SstEnvironmentBuilder.ts"],"sourcesContent":["import {\n type EnvRecord,\n EnvironmentBuilder,\n type EnvironmentBuilderOptions,\n type EnvironmentResolver,\n type InputValue,\n type 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 // Legacy format (dot notation)\n ApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n Postgres = 'sst.aws.Postgres',\n Function = 'sst.aws.Function',\n Bucket = 'sst.aws.Bucket',\n Vpc = 'sst.aws.Vpc',\n Secret = 'sst.sst.Secret',\n\n // Modern format (colon notation)\n SSTSecret = 'sst:sst:Secret',\n SSTFunction = 'sst:sst:Function',\n SSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n SSTPostgres = 'sst:aws:Postgres',\n SSTBucket = 'sst:aws:Bucket',\n SnsTopic = 'sst:aws:SnsTopic',\n}\n\n/**\n * AWS API Gateway V2 resource type.\n * Represents an HTTP/WebSocket API.\n */\nexport type ApiGatewayV2 = {\n type: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n url: 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 type: ResourceType.Postgres | ResourceType.SSTPostgres;\n database: string;\n host: string;\n password: string;\n port: number;\n username: string;\n};\n\n/**\n * AWS Lambda Function resource type.\n */\nexport type Function = {\n type: ResourceType.Function | ResourceType.SSTFunction;\n name: string;\n};\n\n/**\n * AWS S3 Bucket resource type.\n */\nexport type Bucket = {\n type: ResourceType.Bucket | ResourceType.SSTBucket;\n name: string;\n};\n\n/**\n * AWS VPC (Virtual Private Cloud) resource type.\n */\nexport type Vpc = {\n type: ResourceType.Vpc;\n bastion: string;\n};\n\n/**\n * Secret resource type for storing sensitive values.\n */\nexport type Secret = {\n type: ResourceType.Secret | ResourceType.SSTSecret;\n value: string;\n};\n\n/**\n * AWS SNS Topic resource type.\n */\nexport type SnsTopic = {\n type: ResourceType.SnsTopic;\n arn: string;\n};\n\n/**\n * Union type of all supported SST resource types.\n */\nexport type SstResource =\n | ApiGatewayV2\n | Postgres\n | Function\n | Bucket\n | Vpc\n | Secret\n | SnsTopic;\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'>;\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 [name]: value.value,\n});\n\nconst postgresResolver = (key: string, value: PostgresValue) => ({\n [`${key}Name`]: value.database,\n [`${key}Host`]: value.host,\n [`${key}Password`]: value.password,\n [`${key}Port`]: value.port,\n [`${key}Username`]: value.username,\n});\n\nconst bucketResolver = (name: string, value: BucketValue) => ({\n [`${name}Name`]: value.name,\n});\n\nconst topicResolver = (name: string, value: SnsTopicValue) => ({\n [`${name}Arn`]: value.arn,\n});\n\nconst noopResolver = () => ({});\n\n/**\n * Pre-configured resolvers for all SST resource types.\n */\nexport const sstResolvers: Resolvers = {\n // Legacy format\n [ResourceType.ApiGatewayV2]: noopResolver,\n [ResourceType.Function]: noopResolver,\n [ResourceType.Vpc]: noopResolver,\n [ResourceType.Secret]: secretResolver,\n [ResourceType.Postgres]: postgresResolver,\n [ResourceType.Bucket]: bucketResolver,\n\n // Modern format\n [ResourceType.SSTSecret]: secretResolver,\n [ResourceType.SSTBucket]: bucketResolver,\n [ResourceType.SSTFunction]: noopResolver,\n [ResourceType.SSTPostgres]: postgresResolver,\n [ResourceType.SSTApiGatewayV2]: noopResolver,\n [ResourceType.SnsTopic]: topicResolver,\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 [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 AllTypeValues<TRecord>,\n SstResourceTypeString\n>;\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n TRecord extends Record<string, InputValue>,\n TType extends string,\n> = {\n [K in keyof TRecord]: TRecord[K] extends { type: TType }\n ? OmitType<TRecord[K]>\n : 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 CustomTypeValues<TRecord> extends never\n ? Resolvers | undefined\n : {\n [TType in CustomTypeValues<TRecord>]: EnvironmentResolver<\n ValueForType<TRecord, TType>\n >;\n };\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 TRecord extends Record<string, SstResource | InputValue | string>,\n> {\n private readonly builder: EnvironmentBuilder<\n Record<string, InputValue>,\n Resolvers\n >;\n\n /**\n * Create a new SST environment builder.\n *\n * @param record - Object containing SST resources, custom resources, and/or string values\n * @param additionalResolvers - Optional custom resolvers (typed based on custom types in record)\n * @param options - Optional configuration options\n */\n constructor(\n record: TRecord,\n additionalResolvers?: CustomResolvers<TRecord>,\n options?: EnvironmentBuilderOptions,\n ) {\n // Merge resolvers with custom ones taking precedence\n const mergedResolvers: Resolvers = additionalResolvers\n ? { ...sstResolvers, ...additionalResolvers }\n : sstResolvers;\n\n this.builder = new EnvironmentBuilder(\n record as Record<string, InputValue>,\n mergedResolvers,\n options,\n );\n }\n\n /**\n * Build environment variables from the input record.\n *\n * @returns A record of environment variables\n */\n build(): EnvRecord {\n return this.builder.build();\n }\n}\n\n// Re-export useful types\nexport { environmentCase } from './EnvironmentBuilder';\nexport type {\n EnvRecord,\n EnvValue,\n EnvironmentBuilderOptions,\n} from './EnvironmentBuilder';\n"],"mappings":";;;;;;;AAaA,IAAY,wDAAL;AAEL;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;;AACD;AA8FD,MAAM,iBAAiB,CAACA,MAAcC,WAAwB,GAC3D,OAAO,MAAM,MACf;AAED,MAAM,mBAAmB,CAACC,KAAaC,WAA0B;GAC7D,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,YAAY,MAAM;GACxB,EAAE,IAAI,QAAQ,MAAM;GACpB,EAAE,IAAI,YAAY,MAAM;AAC3B;AAED,MAAM,iBAAiB,CAACH,MAAcI,WAAwB,IAC1D,EAAE,KAAK,QAAQ,MAAM,KACxB;AAED,MAAM,gBAAgB,CAACJ,MAAcK,WAA0B,IAC3D,EAAE,KAAK,OAAO,MAAM,IACvB;AAED,MAAM,eAAe,OAAO,CAAE;;;;AAK9B,MAAaC,eAA0B;EAEpC,aAAa,eAAe;EAC5B,aAAa,WAAW;EACxB,aAAa,MAAM;EACnB,aAAa,SAAS;EACtB,aAAa,WAAW;EACxB,aAAa,SAAS;EAGtB,aAAa,YAAY;EACzB,aAAa,YAAY;EACzB,aAAa,cAAc;EAC3B,aAAa,cAAc;EAC3B,aAAa,kBAAkB;EAC/B,aAAa,WAAW;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFD,IAAa,wBAAb,MAEE;CACA,AAAiB;;;;;;;;CAYjB,YACEC,QACAC,qBACAC,SACA;EAEA,MAAMC,kBAA6B,sBAC/B;GAAE,GAAG;GAAc,GAAG;EAAqB,IAC3C;AAEJ,OAAK,UAAU,IAAI,mBACjB,QACA,iBACA;CAEH;;;;;;CAOD,QAAmB;AACjB,SAAO,KAAK,QAAQ,OAAO;CAC5B;AACF"}