@geekmidas/envkit 0.0.4 → 0.0.6

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 (34) hide show
  1. package/dist/{EnvironmentParser-Bo2CCl_K.cjs → EnvironmentParser-BDPDLv6i.cjs} +7 -7
  2. package/dist/EnvironmentParser-C-arQEHQ.d.mts +108 -0
  3. package/dist/{EnvironmentParser-jKrGMBhP.mjs → EnvironmentParser-CQUOGqc0.mjs} +7 -7
  4. package/dist/EnvironmentParser-X4h2Vp4r.d.cts +108 -0
  5. package/dist/EnvironmentParser.cjs +1 -1
  6. package/dist/EnvironmentParser.d.cts +2 -0
  7. package/dist/EnvironmentParser.d.mts +2 -0
  8. package/dist/EnvironmentParser.mjs +1 -1
  9. package/dist/__tests__/ConfigParser.spec.cjs +1 -1
  10. package/dist/__tests__/ConfigParser.spec.d.cts +1 -0
  11. package/dist/__tests__/ConfigParser.spec.d.mts +1 -0
  12. package/dist/__tests__/ConfigParser.spec.mjs +1 -1
  13. package/dist/__tests__/EnvironmentParser.spec.cjs +1 -1
  14. package/dist/__tests__/EnvironmentParser.spec.d.cts +1 -0
  15. package/dist/__tests__/EnvironmentParser.spec.d.mts +1 -0
  16. package/dist/__tests__/EnvironmentParser.spec.mjs +1 -1
  17. package/dist/__tests__/sst.spec.cjs +305 -0
  18. package/dist/__tests__/sst.spec.d.cts +1 -0
  19. package/dist/__tests__/sst.spec.d.mts +1 -0
  20. package/dist/__tests__/sst.spec.mjs +304 -0
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.cts +2 -0
  23. package/dist/index.d.mts +2 -0
  24. package/dist/index.mjs +1 -1
  25. package/dist/sst-BSxwaAdz.cjs +146 -0
  26. package/dist/sst-CQhO0S6y.mjs +128 -0
  27. package/dist/sst.cjs +4 -130
  28. package/dist/sst.d.cts +107 -0
  29. package/dist/sst.d.mts +107 -0
  30. package/dist/sst.mjs +1 -126
  31. package/package.json +5 -5
  32. package/src/EnvironmentParser.ts +10 -10
  33. package/src/__tests__/sst.spec.ts +415 -0
  34. package/src/sst.ts +9 -9
package/dist/sst.mjs CHANGED
@@ -1,128 +1,3 @@
1
- import snakecase from "lodash.snakecase";
1
+ import { ResourceType, environmentCase, normalizeResourceEnv } from "./sst-CQhO0S6y.mjs";
2
2
 
3
- //#region src/sst.ts
4
- /**
5
- * Converts a string to environment variable case format (UPPER_SNAKE_CASE).
6
- * Numbers following underscores are preserved without the underscore.
7
- *
8
- * @param name - The string to convert
9
- * @returns The converted string in environment variable format
10
- *
11
- * @example
12
- * environmentCase('myVariable') // 'MY_VARIABLE'
13
- * environmentCase('api_v2') // 'APIV2'
14
- */
15
- function environmentCase(name) {
16
- return snakecase(name).toUpperCase().replace(/_\d+/g, (r) => {
17
- return r.replace("_", "");
18
- });
19
- }
20
- /**
21
- * Enumeration of supported SST (Serverless Stack Toolkit) resource types.
22
- * Used to identify and process different AWS and SST resources.
23
- */
24
- let ResourceType = /* @__PURE__ */ function(ResourceType$1) {
25
- ResourceType$1["ApiGatewayV2"] = "sst.aws.ApiGatewayV2";
26
- ResourceType$1["Postgres"] = "sst.aws.Postgres";
27
- ResourceType$1["Function"] = "sst.aws.Function";
28
- ResourceType$1["Bucket"] = "sst.aws.Bucket";
29
- ResourceType$1["Vpc"] = "sst.aws.Vpc";
30
- ResourceType$1["Secret"] = "sst.sst.Secret";
31
- ResourceType$1["SSTSecret"] = "sst:sst:Secret";
32
- ResourceType$1["SSTFunction"] = "sst:sst:Function";
33
- ResourceType$1["SSTApiGatewayV2"] = "sst:aws:ApiGatewayV2";
34
- ResourceType$1["SSTPostgres"] = "sst:aws:Postgres";
35
- ResourceType$1["SSTBucket"] = "sst:aws:Bucket";
36
- return ResourceType$1;
37
- }({});
38
- /**
39
- * Processes a Secret resource into environment variables.
40
- *
41
- * @param name - The resource name
42
- * @param value - The Secret resource
43
- * @returns Object with environment variable mappings
44
- */
45
- const secret = (name, value) => ({ [environmentCase(name)]: value.value });
46
- /**
47
- * Processes a Postgres database resource into environment variables.
48
- * Creates multiple environment variables for database connection details.
49
- *
50
- * @param key - The resource key
51
- * @param value - The Postgres resource
52
- * @returns Object with database connection environment variables
53
- */
54
- const postgres = (key, value) => {
55
- const prefix = `${environmentCase(key)}`;
56
- return {
57
- [`${prefix}_NAME`]: value.database,
58
- [`${prefix}_HOST`]: value.host,
59
- [`${prefix}_PASSWORD`]: value.password,
60
- [`${prefix}_PORT`]: value.port,
61
- [`${prefix}_USERNAME`]: value.username
62
- };
63
- };
64
- /**
65
- * Processes a Bucket resource into environment variables.
66
- *
67
- * @param name - The resource name
68
- * @param value - The Bucket resource
69
- * @returns Object with bucket name environment variable
70
- */
71
- const bucket = (name, value) => {
72
- const prefix = `${environmentCase(name)}`;
73
- return { [`${prefix}_NAME`]: value.name };
74
- };
75
- /**
76
- * No-operation processor for resources that don't require environment variables.
77
- *
78
- * @param name - The resource name (unused)
79
- * @param value - The resource value (unused)
80
- * @returns Empty object
81
- */
82
- const noop = (name, value) => ({});
83
- /**
84
- * Map of resource types to their corresponding processor functions.
85
- * Each processor converts resource data into environment variables.
86
- */
87
- const processors = {
88
- [ResourceType.ApiGatewayV2]: noop,
89
- [ResourceType.Function]: noop,
90
- [ResourceType.Vpc]: noop,
91
- [ResourceType.Secret]: secret,
92
- [ResourceType.Postgres]: postgres,
93
- [ResourceType.Bucket]: bucket,
94
- [ResourceType.SSTSecret]: secret,
95
- [ResourceType.SSTBucket]: bucket,
96
- [ResourceType.SSTFunction]: noop,
97
- [ResourceType.SSTPostgres]: postgres,
98
- [ResourceType.SSTApiGatewayV2]: noop
99
- };
100
- /**
101
- * Normalizes SST resources and plain strings into environment variables.
102
- * Processes resources based on their type and converts names to environment case.
103
- *
104
- * @param record - Object containing resources and/or string values
105
- * @returns Normalized environment variables object
106
- *
107
- * @example
108
- * normalizeResourceEnv({
109
- * apiUrl: 'https://api.example.com',
110
- * database: { type: ResourceType.Postgres, ... }
111
- * })
112
- */
113
- function normalizeResourceEnv(record) {
114
- const env = {};
115
- for (const [k, value] of Object.entries(record)) {
116
- if (typeof value === "string") {
117
- env[environmentCase(k)] = value;
118
- continue;
119
- }
120
- const processor = processors[value.type];
121
- if (processor) Object.assign(env, processor(k, value));
122
- else console.warn(`No processor found for resource type: `, { value });
123
- }
124
- return env;
125
- }
126
-
127
- //#endregion
128
3
  export { ResourceType, environmentCase, normalizeResourceEnv };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@geekmidas/envkit",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
+ "types": "./dist/index.d.ts",
8
9
  "import": "./dist/index.mjs",
9
- "require": "./dist/index.cjs",
10
- "types": "./src/index.ts"
10
+ "require": "./dist/index.cjs"
11
11
  },
12
12
  "./sst": {
13
+ "types": "./dist/sst.d.ts",
13
14
  "import": "./dist/sst.mjs",
14
- "require": "./dist/sst.cjs",
15
- "types": "./src/sst.ts"
15
+ "require": "./dist/sst.cjs"
16
16
  }
17
17
  },
18
18
  "publishConfig": {
@@ -5,13 +5,13 @@ import { z } from 'zod/v4';
5
5
  /**
6
6
  * Parses and validates configuration objects against Zod schemas.
7
7
  * Handles nested configurations and aggregates validation errors.
8
- *
8
+ *
9
9
  * @template TResponse - The shape of the configuration object
10
10
  */
11
11
  export class ConfigParser<TResponse extends EmptyObject> {
12
12
  /**
13
13
  * Creates a new ConfigParser instance.
14
- *
14
+ *
15
15
  * @param config - The configuration object to parse
16
16
  */
17
17
  constructor(private readonly config: TResponse) {}
@@ -71,9 +71,9 @@ export class ConfigParser<TResponse extends EmptyObject> {
71
71
  * Parses environment variables with type-safe validation using Zod schemas.
72
72
  * Provides a fluent API for defining environment variable schemas with automatic
73
73
  * error context enrichment.
74
- *
74
+ *
75
75
  * @template T - The type of the configuration object (typically process.env)
76
- *
76
+ *
77
77
  * @example
78
78
  * ```typescript
79
79
  * const config = new EnvironmentParser(process.env)
@@ -89,7 +89,7 @@ export class ConfigParser<TResponse extends EmptyObject> {
89
89
  export class EnvironmentParser<T extends EmptyObject> {
90
90
  /**
91
91
  * Creates a new EnvironmentParser instance.
92
- *
92
+ *
93
93
  * @param config - The configuration object to parse (typically process.env)
94
94
  */
95
95
  constructor(private readonly config: T) {}
@@ -97,7 +97,7 @@ export class EnvironmentParser<T extends EmptyObject> {
97
97
  /**
98
98
  * Wraps a Zod schema to intercept parse/safeParse calls and enrich error messages
99
99
  * with environment variable context.
100
- *
100
+ *
101
101
  * @param schema - The Zod schema to wrap
102
102
  * @param name - The environment variable name for error context
103
103
  * @returns A wrapped Zod schema with enhanced error reporting
@@ -172,7 +172,7 @@ export class EnvironmentParser<T extends EmptyObject> {
172
172
  /**
173
173
  * Creates a proxied version of the Zod object that wraps all schema creators
174
174
  * to provide enhanced error messages with environment variable context.
175
- *
175
+ *
176
176
  * @param name - The environment variable name
177
177
  * @returns A proxied Zod object with wrapped schema creators
178
178
  */
@@ -234,7 +234,7 @@ export class EnvironmentParser<T extends EmptyObject> {
234
234
  /**
235
235
  * Infers the TypeScript type of a configuration object based on its Zod schemas.
236
236
  * Recursively processes nested objects and extracts types from Zod schemas.
237
- *
237
+ *
238
238
  * @template T - The configuration object type
239
239
  */
240
240
  export type InferConfig<T extends EmptyObject> = {
@@ -248,7 +248,7 @@ export type InferConfig<T extends EmptyObject> = {
248
248
  /**
249
249
  * Function type for fetching environment variables with Zod validation.
250
250
  * Returns a Zod object scoped to a specific environment variable.
251
- *
251
+ *
252
252
  * @template TPath - The environment variable path type
253
253
  * @param name - The environment variable name
254
254
  * @returns A Zod object for defining the schema
@@ -260,7 +260,7 @@ export type EnvFetcher<TPath extends string = string> = (
260
260
  /**
261
261
  * Function type for building environment configuration objects.
262
262
  * Takes an EnvFetcher and returns a configuration object with Zod schemas.
263
- *
263
+ *
264
264
  * @template TResponse - The response configuration object type
265
265
  * @param get - The environment variable fetcher function
266
266
  * @returns The configuration object with Zod schemas
@@ -0,0 +1,415 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import {
3
+ type ApiGatewayV2,
4
+ type Bucket,
5
+ type Function,
6
+ type Postgres,
7
+ ResourceType,
8
+ type Secret,
9
+ type Vpc,
10
+ environmentCase,
11
+ normalizeResourceEnv,
12
+ } from '../sst';
13
+
14
+ describe('sst', () => {
15
+ describe('environmentCase', () => {
16
+ it('should convert camelCase to UPPER_SNAKE_CASE', () => {
17
+ expect(environmentCase('myVariable')).toBe('MY_VARIABLE');
18
+ expect(environmentCase('somePropertyName')).toBe('SOME_PROPERTY_NAME');
19
+ expect(environmentCase('APIKey')).toBe('API_KEY');
20
+ });
21
+
22
+ it('should convert snake_case to UPPER_SNAKE_CASE', () => {
23
+ expect(environmentCase('my_variable')).toBe('MY_VARIABLE');
24
+ expect(environmentCase('some_property_name')).toBe('SOME_PROPERTY_NAME');
25
+ });
26
+
27
+ it('should handle numbers correctly', () => {
28
+ // The function only removes underscore before digits
29
+ expect(environmentCase('api_v2')).toBe('API_V2');
30
+ expect(environmentCase('value_123')).toBe('VALUE123');
31
+ expect(environmentCase('test_1_thing')).toBe('TEST1_THING');
32
+ expect(environmentCase('api_2')).toBe('API2');
33
+ });
34
+
35
+ it('should handle already uppercase strings', () => {
36
+ expect(environmentCase('ALREADY_UPPER')).toBe('ALREADY_UPPER');
37
+ expect(environmentCase('TEST')).toBe('TEST');
38
+ });
39
+
40
+ it('should handle kebab-case', () => {
41
+ expect(environmentCase('my-variable')).toBe('MY_VARIABLE');
42
+ expect(environmentCase('kebab-case-example')).toBe('KEBAB_CASE_EXAMPLE');
43
+ });
44
+
45
+ it('should handle mixed cases', () => {
46
+ expect(environmentCase('MixedCASE')).toBe('MIXED_CASE');
47
+ expect(environmentCase('XMLParser')).toBe('XML_PARSER');
48
+ expect(environmentCase('IOStream')).toBe('IO_STREAM');
49
+ });
50
+
51
+ it('should handle empty string', () => {
52
+ expect(environmentCase('')).toBe('');
53
+ });
54
+
55
+ it('should handle single character', () => {
56
+ expect(environmentCase('a')).toBe('A');
57
+ expect(environmentCase('A')).toBe('A');
58
+ });
59
+
60
+ it('should handle strings with special characters', () => {
61
+ expect(environmentCase('my.variable')).toBe('MY_VARIABLE');
62
+ expect(environmentCase('my@variable')).toBe('MY_VARIABLE');
63
+ expect(environmentCase('my#variable')).toBe('MY_VARIABLE');
64
+ });
65
+ });
66
+
67
+ describe('normalizeResourceEnv', () => {
68
+ describe('string values', () => {
69
+ it('should convert string values to environment case', () => {
70
+ const input = {
71
+ apiUrl: 'https://api.example.com',
72
+ secretKey: 'my-secret-key',
73
+ NODE_ENV: 'production',
74
+ };
75
+
76
+ const result = normalizeResourceEnv(input);
77
+
78
+ expect(result).toEqual({
79
+ API_URL: 'https://api.example.com',
80
+ SECRET_KEY: 'my-secret-key',
81
+ NODE_ENV: 'production',
82
+ });
83
+ });
84
+
85
+ it('should handle empty object', () => {
86
+ expect(normalizeResourceEnv({})).toEqual({});
87
+ });
88
+ });
89
+
90
+ describe('Secret resource', () => {
91
+ it('should process Secret resource correctly', () => {
92
+ const secret: Secret = {
93
+ type: ResourceType.Secret,
94
+ value: 'super-secret-value',
95
+ };
96
+
97
+ const result = normalizeResourceEnv({
98
+ mySecret: secret,
99
+ });
100
+
101
+ expect(result).toEqual({
102
+ MY_SECRET: 'super-secret-value',
103
+ });
104
+ });
105
+
106
+ it('should process SSTSecret resource correctly', () => {
107
+ const secret = {
108
+ type: ResourceType.SSTSecret as ResourceType.SSTSecret,
109
+ value: 'another-secret',
110
+ };
111
+
112
+ const result = normalizeResourceEnv({
113
+ appSecret: secret as any,
114
+ });
115
+
116
+ expect(result).toEqual({
117
+ APP_SECRET: 'another-secret',
118
+ });
119
+ });
120
+ });
121
+
122
+ describe('Postgres resource', () => {
123
+ it('should process Postgres resource correctly', () => {
124
+ const postgres: Postgres = {
125
+ type: ResourceType.Postgres,
126
+ database: 'myapp',
127
+ host: 'localhost',
128
+ password: 'password123',
129
+ port: 5432,
130
+ username: 'postgres',
131
+ };
132
+
133
+ const result = normalizeResourceEnv({
134
+ database: postgres,
135
+ });
136
+
137
+ expect(result).toEqual({
138
+ DATABASE_NAME: 'myapp',
139
+ DATABASE_HOST: 'localhost',
140
+ DATABASE_PASSWORD: 'password123',
141
+ DATABASE_PORT: 5432,
142
+ DATABASE_USERNAME: 'postgres',
143
+ });
144
+ });
145
+
146
+ it('should process SSTPostgres resource correctly', () => {
147
+ const postgres = {
148
+ type: ResourceType.SSTPostgres as ResourceType.SSTPostgres,
149
+ database: 'prod_db',
150
+ host: 'prod.example.com',
151
+ password: 'prod-password',
152
+ port: 5433,
153
+ username: 'prod_user',
154
+ };
155
+
156
+ const result = normalizeResourceEnv({
157
+ mainDb: postgres as any,
158
+ });
159
+
160
+ expect(result).toEqual({
161
+ MAIN_DB_NAME: 'prod_db',
162
+ MAIN_DB_HOST: 'prod.example.com',
163
+ MAIN_DB_PASSWORD: 'prod-password',
164
+ MAIN_DB_PORT: 5433,
165
+ MAIN_DB_USERNAME: 'prod_user',
166
+ });
167
+ });
168
+ });
169
+
170
+ describe('Bucket resource', () => {
171
+ it('should process Bucket resource correctly', () => {
172
+ const bucket: Bucket = {
173
+ type: ResourceType.Bucket,
174
+ name: 'my-s3-bucket',
175
+ };
176
+
177
+ const result = normalizeResourceEnv({
178
+ uploadBucket: bucket,
179
+ });
180
+
181
+ expect(result).toEqual({
182
+ UPLOAD_BUCKET_NAME: 'my-s3-bucket',
183
+ });
184
+ });
185
+
186
+ it('should process SSTBucket resource correctly', () => {
187
+ const bucket = {
188
+ type: ResourceType.SSTBucket as ResourceType.SSTBucket,
189
+ name: 'assets-bucket-prod',
190
+ };
191
+
192
+ const result = normalizeResourceEnv({
193
+ assetStorage: bucket as any,
194
+ });
195
+
196
+ expect(result).toEqual({
197
+ ASSET_STORAGE_NAME: 'assets-bucket-prod',
198
+ });
199
+ });
200
+ });
201
+
202
+ describe('noop resources', () => {
203
+ it('should not add environment variables for ApiGatewayV2', () => {
204
+ const api: ApiGatewayV2 = {
205
+ type: ResourceType.ApiGatewayV2,
206
+ url: 'https://api.example.com',
207
+ };
208
+
209
+ const result = normalizeResourceEnv({
210
+ api: api,
211
+ });
212
+
213
+ expect(result).toEqual({});
214
+ });
215
+
216
+ it('should not add environment variables for Function', () => {
217
+ const fn: Function = {
218
+ type: ResourceType.Function,
219
+ name: 'my-lambda',
220
+ };
221
+
222
+ const result = normalizeResourceEnv({
223
+ handler: fn,
224
+ });
225
+
226
+ expect(result).toEqual({});
227
+ });
228
+
229
+ it('should not add environment variables for Vpc', () => {
230
+ const vpc: Vpc = {
231
+ type: ResourceType.Vpc,
232
+ bastion: 'bastion-host',
233
+ };
234
+
235
+ const result = normalizeResourceEnv({
236
+ network: vpc,
237
+ });
238
+
239
+ expect(result).toEqual({});
240
+ });
241
+
242
+ it('should handle all SST noop resource types', () => {
243
+ const api = {
244
+ type: ResourceType.SSTApiGatewayV2 as ResourceType.SSTApiGatewayV2,
245
+ url: 'https://api.example.com',
246
+ };
247
+
248
+ const fn = {
249
+ type: ResourceType.SSTFunction as ResourceType.SSTFunction,
250
+ name: 'my-function',
251
+ };
252
+
253
+ const result = normalizeResourceEnv({
254
+ api: api as any,
255
+ function: fn as any,
256
+ });
257
+
258
+ expect(result).toEqual({});
259
+ });
260
+ });
261
+
262
+ describe('mixed resources', () => {
263
+ it('should handle mix of strings and resources', () => {
264
+ const postgres: Postgres = {
265
+ type: ResourceType.Postgres,
266
+ database: 'app_db',
267
+ host: 'db.example.com',
268
+ password: 'db-pass',
269
+ port: 5432,
270
+ username: 'app_user',
271
+ };
272
+
273
+ const secret: Secret = {
274
+ type: ResourceType.Secret,
275
+ value: 'jwt-secret',
276
+ };
277
+
278
+ const bucket: Bucket = {
279
+ type: ResourceType.Bucket,
280
+ name: 'uploads-bucket',
281
+ };
282
+
283
+ const result = normalizeResourceEnv({
284
+ nodeEnv: 'production',
285
+ appName: 'My App',
286
+ database: postgres,
287
+ jwtSecret: secret,
288
+ uploads: bucket,
289
+ apiVersion: 'v2',
290
+ });
291
+
292
+ expect(result).toEqual({
293
+ NODE_ENV: 'production',
294
+ APP_NAME: 'My App',
295
+ DATABASE_NAME: 'app_db',
296
+ DATABASE_HOST: 'db.example.com',
297
+ DATABASE_PASSWORD: 'db-pass',
298
+ DATABASE_PORT: 5432,
299
+ DATABASE_USERNAME: 'app_user',
300
+ JWT_SECRET: 'jwt-secret',
301
+ UPLOADS_NAME: 'uploads-bucket',
302
+ API_VERSION: 'v2',
303
+ });
304
+ });
305
+ });
306
+
307
+ describe('edge cases', () => {
308
+ it('should warn for unknown resource types', () => {
309
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
310
+
311
+ const unknownResource = {
312
+ type: 'unknown.resource.Type' as any,
313
+ value: 'something',
314
+ };
315
+
316
+ const result = normalizeResourceEnv({
317
+ unknown: unknownResource,
318
+ });
319
+
320
+ expect(result).toEqual({});
321
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
322
+ 'No processor found for resource type: ',
323
+ { value: unknownResource }
324
+ );
325
+
326
+ consoleWarnSpy.mockRestore();
327
+ });
328
+
329
+ it('should handle resources with special characters in keys', () => {
330
+ const secret: Secret = {
331
+ type: ResourceType.Secret,
332
+ value: 'value',
333
+ };
334
+
335
+ const result = normalizeResourceEnv({
336
+ 'my-secret-key': secret,
337
+ 'another.secret': secret,
338
+ 'secret@123': secret,
339
+ });
340
+
341
+ expect(result).toEqual({
342
+ MY_SECRET_KEY: 'value',
343
+ ANOTHER_SECRET: 'value',
344
+ SECRET123: 'value',
345
+ });
346
+ });
347
+
348
+ it('should handle numeric values in postgres port', () => {
349
+ const postgres: Postgres = {
350
+ type: ResourceType.Postgres,
351
+ database: 'test',
352
+ host: 'localhost',
353
+ password: 'pass',
354
+ port: 5432,
355
+ username: 'user',
356
+ };
357
+
358
+ const result = normalizeResourceEnv({
359
+ db: postgres,
360
+ });
361
+
362
+ expect(result.DB_PORT).toBe(5432);
363
+ expect(typeof result.DB_PORT).toBe('number');
364
+ });
365
+
366
+ it('should handle very long keys', () => {
367
+ const secret: Secret = {
368
+ type: ResourceType.Secret,
369
+ value: 'value',
370
+ };
371
+
372
+ const result = normalizeResourceEnv({
373
+ thisIsAVeryLongKeyNameThatShouldBeConvertedProperly: secret,
374
+ });
375
+
376
+ expect(result).toEqual({
377
+ THIS_IS_A_VERY_LONG_KEY_NAME_THAT_SHOULD_BE_CONVERTED_PROPERLY: 'value',
378
+ });
379
+ });
380
+
381
+ it('should handle multiple underscores and numbers', () => {
382
+ const bucket: Bucket = {
383
+ type: ResourceType.Bucket,
384
+ name: 'test-bucket',
385
+ };
386
+
387
+ const result = normalizeResourceEnv({
388
+ 's3_bucket_v2_1': bucket,
389
+ 'bucket_123_456': bucket,
390
+ });
391
+
392
+ expect(result).toEqual({
393
+ S3_BUCKET_V21_NAME: 'test-bucket',
394
+ BUCKET123456_NAME: 'test-bucket',
395
+ });
396
+ });
397
+ });
398
+ });
399
+
400
+ describe('ResourceType enum', () => {
401
+ it('should have all expected resource types', () => {
402
+ expect(ResourceType.ApiGatewayV2).toBe('sst.aws.ApiGatewayV2');
403
+ expect(ResourceType.Postgres).toBe('sst.aws.Postgres');
404
+ expect(ResourceType.Function).toBe('sst.aws.Function');
405
+ expect(ResourceType.Bucket).toBe('sst.aws.Bucket');
406
+ expect(ResourceType.Vpc).toBe('sst.aws.Vpc');
407
+ expect(ResourceType.Secret).toBe('sst.sst.Secret');
408
+ expect(ResourceType.SSTSecret).toBe('sst:sst:Secret');
409
+ expect(ResourceType.SSTFunction).toBe('sst:sst:Function');
410
+ expect(ResourceType.SSTApiGatewayV2).toBe('sst:aws:ApiGatewayV2');
411
+ expect(ResourceType.SSTPostgres).toBe('sst:aws:Postgres');
412
+ expect(ResourceType.SSTBucket).toBe('sst:aws:Bucket');
413
+ });
414
+ });
415
+ });