@geekmidas/cli 0.0.26 → 0.2.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 (121) hide show
  1. package/FUNCTION_CRON_SUPPORT.md +266 -0
  2. package/README.md +84 -17
  3. package/dist/CronGenerator-1PflEYe2.cjs +60 -0
  4. package/dist/CronGenerator-1PflEYe2.cjs.map +1 -0
  5. package/dist/CronGenerator-DXRfHQcV.mjs +54 -0
  6. package/dist/CronGenerator-DXRfHQcV.mjs.map +1 -0
  7. package/dist/EndpointGenerator-BbGrDiCP.cjs +264 -0
  8. package/dist/EndpointGenerator-BbGrDiCP.cjs.map +1 -0
  9. package/dist/EndpointGenerator-BmZ9BxbO.mjs +258 -0
  10. package/dist/EndpointGenerator-BmZ9BxbO.mjs.map +1 -0
  11. package/dist/FunctionGenerator-Clw64SwQ.cjs +59 -0
  12. package/dist/FunctionGenerator-Clw64SwQ.cjs.map +1 -0
  13. package/dist/FunctionGenerator-DOEB_yPh.mjs +53 -0
  14. package/dist/FunctionGenerator-DOEB_yPh.mjs.map +1 -0
  15. package/dist/Generator-CDoEXCDg.cjs +47 -0
  16. package/dist/Generator-CDoEXCDg.cjs.map +1 -0
  17. package/dist/Generator-UanJW0_V.mjs +41 -0
  18. package/dist/Generator-UanJW0_V.mjs.map +1 -0
  19. package/dist/SubscriberGenerator-BfMZCVNy.cjs +204 -0
  20. package/dist/SubscriberGenerator-BfMZCVNy.cjs.map +1 -0
  21. package/dist/SubscriberGenerator-D2u00NI3.mjs +198 -0
  22. package/dist/SubscriberGenerator-D2u00NI3.mjs.map +1 -0
  23. package/dist/build/index.cjs +12 -0
  24. package/dist/build/index.mjs +12 -0
  25. package/dist/build/manifests.cjs +3 -0
  26. package/dist/build/manifests.mjs +3 -0
  27. package/dist/build/providerResolver.cjs +5 -0
  28. package/dist/build/providerResolver.mjs +3 -0
  29. package/dist/build/types.cjs +0 -0
  30. package/dist/build/types.mjs +0 -0
  31. package/dist/build-BBhlEjf5.cjs +89 -0
  32. package/dist/build-BBhlEjf5.cjs.map +1 -0
  33. package/dist/build-kY-lG30Q.mjs +83 -0
  34. package/dist/build-kY-lG30Q.mjs.map +1 -0
  35. package/dist/config-D1EpSGk6.cjs +36 -0
  36. package/dist/config-D1EpSGk6.cjs.map +1 -0
  37. package/dist/config-U-mdW-7Y.mjs +30 -0
  38. package/dist/config-U-mdW-7Y.mjs.map +1 -0
  39. package/dist/config.cjs +1 -1
  40. package/dist/config.mjs +1 -1
  41. package/dist/generators/CronGenerator.cjs +4 -0
  42. package/dist/generators/CronGenerator.mjs +4 -0
  43. package/dist/generators/EndpointGenerator.cjs +4 -0
  44. package/dist/generators/EndpointGenerator.mjs +4 -0
  45. package/dist/generators/FunctionGenerator.cjs +4 -0
  46. package/dist/generators/FunctionGenerator.mjs +4 -0
  47. package/dist/generators/Generator.cjs +3 -0
  48. package/dist/generators/Generator.mjs +3 -0
  49. package/dist/generators/SubscriberGenerator.cjs +4 -0
  50. package/dist/generators/SubscriberGenerator.mjs +4 -0
  51. package/dist/generators/index.cjs +12 -0
  52. package/dist/generators/index.mjs +8 -0
  53. package/dist/generators-CEKtVh81.cjs +0 -0
  54. package/dist/generators-CsLujGXs.mjs +0 -0
  55. package/dist/index.cjs +71 -25
  56. package/dist/index.cjs.map +1 -0
  57. package/dist/index.mjs +71 -25
  58. package/dist/index.mjs.map +1 -0
  59. package/dist/manifests-BrJXpHrf.mjs +21 -0
  60. package/dist/manifests-BrJXpHrf.mjs.map +1 -0
  61. package/dist/manifests-D0saShvH.cjs +27 -0
  62. package/dist/manifests-D0saShvH.cjs.map +1 -0
  63. package/dist/{openapi-CksVdkh2.mjs → openapi-BQx3_JbM.mjs} +8 -6
  64. package/dist/openapi-BQx3_JbM.mjs.map +1 -0
  65. package/dist/{openapi-D4QQJUPY.cjs → openapi-CMLr04cz.cjs} +9 -7
  66. package/dist/openapi-CMLr04cz.cjs.map +1 -0
  67. package/dist/{openapi-react-query-DpT3XHFC.mjs → openapi-react-query-DbrWwQzb.mjs} +5 -3
  68. package/dist/openapi-react-query-DbrWwQzb.mjs.map +1 -0
  69. package/dist/{openapi-react-query-C1JLYUOs.cjs → openapi-react-query-Dvjqx_Eo.cjs} +5 -3
  70. package/dist/openapi-react-query-Dvjqx_Eo.cjs.map +1 -0
  71. package/dist/openapi-react-query.cjs +1 -1
  72. package/dist/openapi-react-query.mjs +1 -1
  73. package/dist/openapi.cjs +4 -3
  74. package/dist/openapi.mjs +4 -3
  75. package/dist/providerResolver-B_TjNF0_.mjs +96 -0
  76. package/dist/providerResolver-B_TjNF0_.mjs.map +1 -0
  77. package/dist/providerResolver-DgvzNfP4.cjs +114 -0
  78. package/dist/providerResolver-DgvzNfP4.cjs.map +1 -0
  79. package/examples/cron-example.ts +45 -0
  80. package/examples/function-example.ts +40 -0
  81. package/examples/gkm.config.json +22 -0
  82. package/examples/gkm.minimal.config.json +7 -0
  83. package/examples/gkm.production.config.json +27 -0
  84. package/examples/logger.ts +1 -1
  85. package/package.json +38 -14
  86. package/src/__tests__/config.spec.ts +110 -0
  87. package/src/__tests__/openapi-react-query.spec.ts +506 -0
  88. package/src/__tests__/openapi.spec.ts +362 -0
  89. package/src/__tests__/test-helpers.ts +180 -0
  90. package/src/build/__tests__/index-new.spec.ts +577 -0
  91. package/src/build/index.ts +197 -0
  92. package/src/build/manifests.ts +35 -0
  93. package/src/build/providerResolver.ts +184 -0
  94. package/src/build/types.ts +37 -0
  95. package/src/config.ts +14 -6
  96. package/src/generators/CronGenerator.ts +98 -0
  97. package/src/generators/EndpointGenerator.ts +389 -0
  98. package/src/generators/FunctionGenerator.ts +97 -0
  99. package/src/generators/Generator.ts +95 -0
  100. package/src/generators/SubscriberGenerator.ts +271 -0
  101. package/src/generators/__tests__/CronGenerator.spec.ts +445 -0
  102. package/src/generators/__tests__/EndpointGenerator.spec.ts +394 -0
  103. package/src/generators/__tests__/FunctionGenerator.spec.ts +256 -0
  104. package/src/generators/__tests__/SubscriberGenerator.spec.ts +341 -0
  105. package/src/generators/index.ts +9 -0
  106. package/src/index.ts +57 -22
  107. package/src/openapi-react-query.ts +2 -1
  108. package/src/openapi.ts +5 -4
  109. package/src/types.ts +91 -2
  110. package/dist/build-BTggTCYL.cjs +0 -176
  111. package/dist/build-Ca4P6_lY.mjs +0 -170
  112. package/dist/build.cjs +0 -5
  113. package/dist/build.mjs +0 -5
  114. package/dist/config-BNqUMsvc.cjs +0 -24
  115. package/dist/config-BciAdY6_.mjs +0 -18
  116. package/dist/loadEndpoints-BBIavB9h.cjs +0 -37
  117. package/dist/loadEndpoints-DAZ53Og2.mjs +0 -31
  118. package/dist/loadEndpoints.cjs +0 -3
  119. package/dist/loadEndpoints.mjs +0 -3
  120. package/src/build.ts +0 -305
  121. package/src/loadEndpoints.ts +0 -48
@@ -0,0 +1,577 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { itWithDir } from '@geekmidas/testkit/os';
4
+ import { describe, expect, vi } from 'vitest';
5
+ import {
6
+ createMockCronFile,
7
+ createMockEndpointFile,
8
+ createMockFunctionFile,
9
+ createTestFile,
10
+ } from '../../__tests__/test-helpers';
11
+ import { buildCommand } from '../index';
12
+
13
+ describe('buildCommand', () => {
14
+ itWithDir(
15
+ 'should build endpoints, functions, and crons for multiple providers',
16
+ async ({ dir }) => {
17
+ // Create test files that will be discovered
18
+ await createMockEndpointFile(
19
+ dir,
20
+ 'src/endpoints/users.ts',
21
+ 'getUsersEndpoint',
22
+ '/users',
23
+ 'GET',
24
+ );
25
+ await createMockEndpointFile(
26
+ dir,
27
+ 'src/endpoints/posts.ts',
28
+ 'getPostsEndpoint',
29
+ '/posts',
30
+ 'GET',
31
+ );
32
+ await createMockFunctionFile(
33
+ dir,
34
+ 'src/functions/process.ts',
35
+ 'processDataFunction',
36
+ 60,
37
+ );
38
+ await createMockCronFile(
39
+ dir,
40
+ 'src/crons/cleanup.ts',
41
+ 'cleanupCron',
42
+ 'rate(1 day)',
43
+ );
44
+
45
+ // Create a basic config file
46
+ await createTestFile(
47
+ dir,
48
+ 'gkm.config.ts',
49
+ `
50
+ export default {
51
+ routes: './src/endpoints/**/*.ts',
52
+ functions: './src/functions/**/*.ts',
53
+ crons: './src/crons/**/*.ts',
54
+ envParser: './config/env',
55
+ logger: './config/logger',
56
+ };
57
+ `,
58
+ );
59
+
60
+ // Create env and logger files
61
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
62
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
63
+
64
+ const originalCwd = process.cwd();
65
+ process.chdir(dir);
66
+
67
+ try {
68
+ await buildCommand({ provider: 'server' });
69
+
70
+ // Check that output directories were created
71
+ const serverDir = join(dir, '.gkm', 'server');
72
+
73
+ // Check app.ts has the createApp function with new API
74
+ const appContent = await readFile(join(serverDir, 'app.ts'), 'utf-8');
75
+ expect(appContent).toContain('function createApp');
76
+ expect(appContent).toContain('interface ServerApp');
77
+ expect(appContent).toContain('async start(options');
78
+
79
+ // Check endpoints.ts has the HonoEndpoint setup
80
+ const endpointsContent = await readFile(
81
+ join(serverDir, 'endpoints.ts'),
82
+ 'utf-8',
83
+ );
84
+ expect(endpointsContent).toContain('HonoEndpoint');
85
+ } finally {
86
+ process.chdir(originalCwd);
87
+ }
88
+ },
89
+ );
90
+
91
+ itWithDir(
92
+ 'should perform complete build with all construct types for AWS Lambda',
93
+ async ({ dir }) => {
94
+ // Create comprehensive test setup with all construct types
95
+ await createMockEndpointFile(
96
+ dir,
97
+ 'src/endpoints/users.ts',
98
+ 'getUsersEndpoint',
99
+ '/users',
100
+ 'GET',
101
+ );
102
+ await createMockEndpointFile(
103
+ dir,
104
+ 'src/endpoints/posts.ts',
105
+ 'getPostsEndpoint',
106
+ '/posts',
107
+ 'POST',
108
+ );
109
+ await createMockFunctionFile(
110
+ dir,
111
+ 'src/functions/processData.ts',
112
+ 'processDataFunction',
113
+ 300,
114
+ );
115
+ await createMockFunctionFile(
116
+ dir,
117
+ 'src/functions/sendEmail.ts',
118
+ 'sendEmailFunction',
119
+ 30,
120
+ );
121
+ await createMockCronFile(
122
+ dir,
123
+ 'src/crons/dailyCleanup.ts',
124
+ 'dailyCleanupCron',
125
+ 'rate(1 day)',
126
+ );
127
+ await createMockCronFile(
128
+ dir,
129
+ 'src/crons/hourlyReport.ts',
130
+ 'hourlyReportCron',
131
+ 'cron(0 * * * ? *)',
132
+ );
133
+
134
+ // Create config
135
+ await createTestFile(
136
+ dir,
137
+ 'gkm.config.ts',
138
+ `
139
+ export default {
140
+ routes: './src/endpoints/**/*.ts',
141
+ functions: './src/functions/**/*.ts',
142
+ crons: './src/crons/**/*.ts',
143
+ envParser: './config/env',
144
+ logger: './config/logger',
145
+ };
146
+ `,
147
+ );
148
+
149
+ // Create env and logger files
150
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
151
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
152
+
153
+ const originalCwd = process.cwd();
154
+ process.chdir(dir);
155
+
156
+ try {
157
+ // Build for AWS Lambda
158
+ await buildCommand({ provider: 'aws' });
159
+
160
+ const awsLambdaDir = join(dir, '.gkm', 'aws-lambda');
161
+ const awsApiGatewayV2Dir = join(dir, '.gkm', 'aws-apigatewayv2');
162
+
163
+ // Verify Lambda handlers were created
164
+ expect(
165
+ await readFile(
166
+ join(awsLambdaDir, 'functions', 'processDataFunction.ts'),
167
+ 'utf-8',
168
+ ),
169
+ ).toContain('AWSLambdaFunction');
170
+ expect(
171
+ await readFile(
172
+ join(awsLambdaDir, 'functions', 'sendEmailFunction.ts'),
173
+ 'utf-8',
174
+ ),
175
+ ).toContain('AWSLambdaFunction');
176
+
177
+ // Verify Cron handlers were created
178
+ expect(
179
+ await readFile(
180
+ join(awsLambdaDir, 'crons', 'dailyCleanupCron.ts'),
181
+ 'utf-8',
182
+ ),
183
+ ).toContain('AWSScheduledFunction');
184
+ expect(
185
+ await readFile(
186
+ join(awsLambdaDir, 'crons', 'hourlyReportCron.ts'),
187
+ 'utf-8',
188
+ ),
189
+ ).toContain('AWSScheduledFunction');
190
+
191
+ // Verify API Gateway handlers were created
192
+ expect(
193
+ await readFile(
194
+ join(awsApiGatewayV2Dir, 'getUsersEndpoint.ts'),
195
+ 'utf-8',
196
+ ),
197
+ ).toContain('AmazonApiGatewayV2Endpoint');
198
+ expect(
199
+ await readFile(
200
+ join(awsApiGatewayV2Dir, 'getPostsEndpoint.ts'),
201
+ 'utf-8',
202
+ ),
203
+ ).toContain('AmazonApiGatewayV2Endpoint');
204
+
205
+ // Verify unified manifest was created at root .gkm directory
206
+ const manifestPath = join(dir, '.gkm', 'manifest.json');
207
+ const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
208
+
209
+ // Verify manifest structure includes all routes from both providers
210
+ expect(manifest).toMatchObject({
211
+ routes: expect.arrayContaining([
212
+ // Routes from aws-lambda provider
213
+ expect.objectContaining({
214
+ path: '/users',
215
+ method: 'GET',
216
+ handler: expect.stringContaining(
217
+ 'routes/getUsersEndpoint.handler',
218
+ ),
219
+ }),
220
+ expect.objectContaining({
221
+ path: '/posts',
222
+ method: 'POST',
223
+ handler: expect.stringContaining(
224
+ 'routes/getPostsEndpoint.handler',
225
+ ),
226
+ }),
227
+ // Routes from aws-apigatewayv2 provider
228
+ expect.objectContaining({
229
+ path: '/users',
230
+ method: 'GET',
231
+ handler: expect.stringContaining('getUsersEndpoint.handler'),
232
+ }),
233
+ expect.objectContaining({
234
+ path: '/posts',
235
+ method: 'POST',
236
+ handler: expect.stringContaining('getPostsEndpoint.handler'),
237
+ }),
238
+ ]),
239
+ functions: expect.arrayContaining([
240
+ expect.objectContaining({
241
+ name: 'processDataFunction',
242
+ handler: expect.stringContaining(
243
+ 'functions/processDataFunction.handler',
244
+ ),
245
+ timeout: 300,
246
+ }),
247
+ expect.objectContaining({
248
+ name: 'sendEmailFunction',
249
+ handler: expect.stringContaining(
250
+ 'functions/sendEmailFunction.handler',
251
+ ),
252
+ timeout: 30,
253
+ }),
254
+ ]),
255
+ crons: expect.arrayContaining([
256
+ expect.objectContaining({
257
+ name: 'dailyCleanupCron',
258
+ handler: expect.stringContaining(
259
+ 'crons/dailyCleanupCron.handler',
260
+ ),
261
+ schedule: 'rate(1 day)',
262
+ }),
263
+ expect.objectContaining({
264
+ name: 'hourlyReportCron',
265
+ handler: expect.stringContaining(
266
+ 'crons/hourlyReportCron.handler',
267
+ ),
268
+ schedule: 'cron(0 * * * ? *)',
269
+ }),
270
+ ]),
271
+ });
272
+
273
+ // Verify counts - should have duplicated routes (one for each provider)
274
+ expect(manifest.routes).toHaveLength(4); // 2 routes x 2 providers
275
+ expect(manifest.functions).toHaveLength(2);
276
+ expect(manifest.crons).toHaveLength(2);
277
+ } finally {
278
+ process.chdir(originalCwd);
279
+ }
280
+ },
281
+ );
282
+
283
+ itWithDir('should handle case with no constructs found', async ({ dir }) => {
284
+ // Create a basic config file with no actual construct files
285
+ await createTestFile(
286
+ dir,
287
+ 'gkm.config.ts',
288
+ `
289
+ export default {
290
+ routes: './src/endpoints/**/*.ts',
291
+ functions: './src/functions/**/*.ts',
292
+ crons: './src/crons/**/*.ts',
293
+ envParser: './config/env',
294
+ logger: './config/logger',
295
+ };
296
+ `,
297
+ );
298
+
299
+ // Create env and logger files
300
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
301
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
302
+
303
+ const originalCwd = process.cwd();
304
+ process.chdir(dir);
305
+
306
+ const logSpy = vi.spyOn(console, 'log');
307
+
308
+ try {
309
+ await buildCommand({ provider: 'server' });
310
+
311
+ expect(logSpy).toHaveBeenCalledWith('Found 0 endpoints');
312
+ expect(logSpy).toHaveBeenCalledWith('Found 0 functions');
313
+ expect(logSpy).toHaveBeenCalledWith('Found 0 crons');
314
+ expect(logSpy).toHaveBeenCalledWith('Found 0 subscribers');
315
+ expect(logSpy).toHaveBeenCalledWith(
316
+ 'No endpoints, functions, crons, or subscribers found to process',
317
+ );
318
+ } finally {
319
+ process.chdir(originalCwd);
320
+ logSpy.mockRestore();
321
+ }
322
+ });
323
+
324
+ itWithDir(
325
+ 'should handle optional functions and crons config',
326
+ async ({ dir }) => {
327
+ // Create config with undefined functions and crons
328
+ await createTestFile(
329
+ dir,
330
+ 'gkm.config.ts',
331
+ `
332
+ export default {
333
+ routes: './src/endpoints/**/*.ts',
334
+ functions: undefined,
335
+ crons: undefined,
336
+ envParser: './config/env',
337
+ logger: './config/logger',
338
+ };
339
+ `,
340
+ );
341
+
342
+ await createMockEndpointFile(
343
+ dir,
344
+ 'src/endpoints/test.ts',
345
+ 'testEndpoint',
346
+ '/test',
347
+ 'GET',
348
+ );
349
+
350
+ // Create env and logger files
351
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
352
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
353
+
354
+ const originalCwd = process.cwd();
355
+ process.chdir(dir);
356
+
357
+ const logSpy = vi.spyOn(console, 'log');
358
+
359
+ try {
360
+ await buildCommand({ provider: 'server' });
361
+
362
+ expect(logSpy).toHaveBeenCalledWith('Found 1 endpoints');
363
+ expect(logSpy).toHaveBeenCalledWith('Found 0 functions');
364
+ expect(logSpy).toHaveBeenCalledWith('Found 0 crons');
365
+
366
+ // Should not log functions or crons loading messages
367
+ expect(logSpy).not.toHaveBeenCalledWith(
368
+ expect.stringContaining('Loading functions'),
369
+ );
370
+ expect(logSpy).not.toHaveBeenCalledWith(
371
+ expect.stringContaining('Loading crons'),
372
+ );
373
+ } finally {
374
+ process.chdir(originalCwd);
375
+ logSpy.mockRestore();
376
+ }
377
+ },
378
+ );
379
+
380
+ itWithDir(
381
+ 'should parse envParser configuration correctly',
382
+ async ({ dir }) => {
383
+ // Create config with custom named exports
384
+ await createTestFile(
385
+ dir,
386
+ 'gkm.config.ts',
387
+ `
388
+ export default {
389
+ routes: './src/endpoints/**/*.ts',
390
+ functions: undefined,
391
+ crons: undefined,
392
+ envParser: './config/env#customEnvParser',
393
+ logger: './config/logger#customLogger',
394
+ };
395
+ `,
396
+ );
397
+
398
+ await createMockEndpointFile(
399
+ dir,
400
+ 'src/endpoints/test.ts',
401
+ 'testEndpoint',
402
+ '/test',
403
+ 'GET',
404
+ );
405
+
406
+ // Create env and logger files with named exports
407
+ await createTestFile(
408
+ dir,
409
+ 'config/env.ts',
410
+ 'export const customEnvParser = {}',
411
+ );
412
+ await createTestFile(
413
+ dir,
414
+ 'config/logger.ts',
415
+ 'export const customLogger = {}',
416
+ );
417
+
418
+ const originalCwd = process.cwd();
419
+ process.chdir(dir);
420
+
421
+ try {
422
+ await buildCommand({ provider: 'aws' });
423
+
424
+ // Verify that a handler file was generated with correct imports
425
+ const handlerFile = join(dir, '.gkm/aws-apigatewayv2/testEndpoint.ts');
426
+ const handlerContent = await readFile(handlerFile, 'utf-8');
427
+ expect(handlerContent).toContain('{ customEnvParser as envParser }');
428
+ } finally {
429
+ process.chdir(originalCwd);
430
+ }
431
+ },
432
+ );
433
+
434
+ itWithDir(
435
+ 'should create output directories for each provider',
436
+ async ({ dir }) => {
437
+ // Create config with multiple providers
438
+ await createTestFile(
439
+ dir,
440
+ 'gkm.config.ts',
441
+ `
442
+ export default {
443
+ routes: './src/endpoints/**/*.ts',
444
+ functions: undefined,
445
+ crons: undefined,
446
+ envParser: './config/env',
447
+ logger: './config/logger',
448
+ };
449
+ `,
450
+ );
451
+
452
+ await createMockEndpointFile(
453
+ dir,
454
+ 'src/endpoints/test.ts',
455
+ 'testEndpoint',
456
+ '/test',
457
+ 'GET',
458
+ );
459
+
460
+ // Create env and logger files
461
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
462
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
463
+
464
+ const originalCwd = process.cwd();
465
+ process.chdir(dir);
466
+
467
+ try {
468
+ await buildCommand({ provider: 'aws' });
469
+
470
+ const v2HandlerFile = join(
471
+ dir,
472
+ '.gkm/aws-apigatewayv2/testEndpoint.ts',
473
+ );
474
+
475
+ const v2Content = await readFile(v2HandlerFile, 'utf-8');
476
+
477
+ expect(v2Content).toContain('AmazonApiGatewayV2Endpoint');
478
+ } finally {
479
+ process.chdir(originalCwd);
480
+ }
481
+ },
482
+ );
483
+
484
+ itWithDir(
485
+ 'should handle default import patterns for envParser and logger',
486
+ async ({ dir }) => {
487
+ // Create config with default import patterns
488
+ await createTestFile(
489
+ dir,
490
+ 'gkm.config.ts',
491
+ `
492
+ export default {
493
+ routes: './src/endpoints/**/*.ts',
494
+ functions: undefined,
495
+ crons: undefined,
496
+ envParser: './config/env',
497
+ logger: './config/logger',
498
+ };
499
+ `,
500
+ );
501
+
502
+ await createMockEndpointFile(
503
+ dir,
504
+ 'src/endpoints/test.ts',
505
+ 'testEndpoint',
506
+ '/test',
507
+ 'GET',
508
+ );
509
+
510
+ // Create env and logger files with default exports
511
+ await createTestFile(dir, 'config/env.ts', 'export default {}');
512
+ await createTestFile(dir, 'config/logger.ts', 'export default {}');
513
+
514
+ const originalCwd = process.cwd();
515
+ process.chdir(dir);
516
+
517
+ try {
518
+ await buildCommand({ provider: 'aws' });
519
+
520
+ // Verify that a handler file was generated with default imports
521
+ const handlerFile = join(dir, '.gkm/aws-apigatewayv2/testEndpoint.ts');
522
+ const handlerContent = await readFile(handlerFile, 'utf-8');
523
+ expect(handlerContent).toContain('import envParser');
524
+ expect(handlerContent).not.toContain('{ envParser }');
525
+ } finally {
526
+ process.chdir(originalCwd);
527
+ }
528
+ },
529
+ );
530
+
531
+ itWithDir(
532
+ 'should handle envParser pattern with same name as expected',
533
+ async ({ dir }) => {
534
+ // Create config with named exports that match expected names
535
+ await createTestFile(
536
+ dir,
537
+ 'gkm.config.ts',
538
+ `
539
+ export default {
540
+ routes: './src/endpoints/**/*.ts',
541
+ functions: undefined,
542
+ crons: undefined,
543
+ envParser: './config/env#envParser',
544
+ logger: './config/logger#logger',
545
+ };
546
+ `,
547
+ );
548
+
549
+ await createMockEndpointFile(
550
+ dir,
551
+ 'src/endpoints/test.ts',
552
+ 'testEndpoint',
553
+ '/test',
554
+ 'GET',
555
+ );
556
+
557
+ // Create env and logger files with named exports
558
+ await createTestFile(dir, 'config/env.ts', 'export const envParser = {}');
559
+ await createTestFile(dir, 'config/logger.ts', 'export const logger = {}');
560
+
561
+ const originalCwd = process.cwd();
562
+ process.chdir(dir);
563
+
564
+ try {
565
+ await buildCommand({ provider: 'aws' });
566
+
567
+ // Verify that a handler file was generated with named imports
568
+ const handlerFile = join(dir, '.gkm/aws-apigatewayv2/testEndpoint.ts');
569
+ const handlerContent = await readFile(handlerFile, 'utf-8');
570
+
571
+ expect(handlerContent).toContain('{ envParser }');
572
+ } finally {
573
+ process.chdir(originalCwd);
574
+ }
575
+ },
576
+ );
577
+ });