@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,341 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import {
4
+ type Subscriber,
5
+ SubscriberBuilder,
6
+ } from '@geekmidas/constructs/subscribers';
7
+
8
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
9
+ import {
10
+ cleanupDir,
11
+ createMockBuildContext,
12
+ createTempDir,
13
+ } from '../../__tests__/test-helpers';
14
+ import type { GeneratedConstruct } from '../Generator';
15
+ import { SubscriberGenerator } from '../SubscriberGenerator';
16
+
17
+ describe('SubscriberGenerator', () => {
18
+ let tempDir: string;
19
+ let outputDir: string;
20
+ let generator: SubscriberGenerator;
21
+ let context: ReturnType<typeof createMockBuildContext>;
22
+
23
+ beforeEach(async () => {
24
+ tempDir = await createTempDir();
25
+ outputDir = join(tempDir, 'output');
26
+ generator = new SubscriberGenerator();
27
+ context = createMockBuildContext();
28
+ });
29
+
30
+ afterEach(async () => {
31
+ await cleanupDir(tempDir);
32
+ });
33
+
34
+ describe('isConstruct', () => {
35
+ it('should identify valid subscribers', async () => {
36
+ const testSubscriber = new SubscriberBuilder()
37
+ .subscribe(['user.created'] as any)
38
+ .handle(async ({ events, logger }) => {
39
+ logger.info({ eventCount: events.length }, 'Processing events');
40
+ });
41
+
42
+ expect(generator.isConstruct(testSubscriber)).toBe(true);
43
+ });
44
+
45
+ it('should reject invalid constructs', () => {
46
+ expect(generator.isConstruct({})).toBe(false);
47
+ expect(generator.isConstruct('string')).toBe(false);
48
+ expect(generator.isConstruct(null)).toBe(false);
49
+ });
50
+ });
51
+
52
+ describe('build', () => {
53
+ const createSubscriberConstruct = (
54
+ key: string,
55
+ subscribedEvents: string[],
56
+ timeout: number = 30000,
57
+ ): GeneratedConstruct<Subscriber<any, any, any, any, any, any>> => {
58
+ const subscriber = new SubscriberBuilder()
59
+ .subscribe(subscribedEvents as any)
60
+ .timeout(timeout)
61
+ .handle(async ({ events, logger }) => {
62
+ logger.info({ eventCount: events.length }, 'Processing events');
63
+ });
64
+
65
+ return {
66
+ key,
67
+ name: key.toLowerCase(),
68
+ construct: subscriber,
69
+ path: {
70
+ absolute: join(tempDir, `${key}.ts`),
71
+ relative: `${key}.ts`,
72
+ },
73
+ };
74
+ };
75
+
76
+ it('should generate subscriber handlers', async () => {
77
+ const constructs = [
78
+ createSubscriberConstruct('userEventSubscriber', [
79
+ 'user.created',
80
+ 'user.updated',
81
+ ]),
82
+ createSubscriberConstruct('orderEventSubscriber', ['order.placed']),
83
+ ];
84
+
85
+ const subscriberInfos = await generator.build(
86
+ context,
87
+ constructs,
88
+ outputDir,
89
+ { provider: 'aws-lambda' },
90
+ );
91
+
92
+ expect(subscriberInfos).toHaveLength(2);
93
+ expect(subscriberInfos[0]).toMatchObject({
94
+ name: 'userEventSubscriber',
95
+ handler: expect.stringContaining(
96
+ 'subscribers/userEventSubscriber.handler',
97
+ ),
98
+ subscribedEvents: ['user.created', 'user.updated'],
99
+ timeout: 30000,
100
+ });
101
+ expect(subscriberInfos[1]).toMatchObject({
102
+ name: 'orderEventSubscriber',
103
+ handler: expect.stringContaining(
104
+ 'subscribers/orderEventSubscriber.handler',
105
+ ),
106
+ subscribedEvents: ['order.placed'],
107
+ timeout: 30000,
108
+ });
109
+
110
+ // Check that handler files were created
111
+ const userHandlerPath = join(
112
+ outputDir,
113
+ 'subscribers',
114
+ 'userEventSubscriber.ts',
115
+ );
116
+ const userContent = await readFile(userHandlerPath, 'utf-8');
117
+ expect(userContent).toContain('AWSLambdaSubscriber');
118
+ expect(userContent).toContain('import { userEventSubscriber }');
119
+ expect(userContent).toContain('import envParser');
120
+
121
+ const orderHandlerPath = join(
122
+ outputDir,
123
+ 'subscribers',
124
+ 'orderEventSubscriber.ts',
125
+ );
126
+ const orderContent = await readFile(orderHandlerPath, 'utf-8');
127
+ expect(orderContent).toContain('AWSLambdaSubscriber');
128
+ expect(orderContent).toContain('import { orderEventSubscriber }');
129
+ });
130
+
131
+ it('should generate correct relative import paths', async () => {
132
+ const subscriber = new SubscriberBuilder()
133
+ .subscribe(['event.type'] as any)
134
+ .timeout(45000)
135
+ .handle(async ({ events, logger }) => {
136
+ logger.info({ eventCount: events.length }, 'Processing events');
137
+ });
138
+
139
+ const construct: GeneratedConstruct<
140
+ Subscriber<any, any, any, any, any, any>
141
+ > = {
142
+ key: 'deepSubscriber',
143
+ name: 'deep-subscriber',
144
+ construct: subscriber,
145
+ path: {
146
+ absolute: join(tempDir, 'src/subscribers/deep/processor.ts'),
147
+ relative: 'src/subscribers/deep/processor.ts',
148
+ },
149
+ };
150
+
151
+ await generator.build(context, [construct], outputDir);
152
+
153
+ const handlerPath = join(outputDir, 'subscribers', 'deepSubscriber.ts');
154
+ const handlerContent = await readFile(handlerPath, 'utf-8');
155
+
156
+ // Check relative imports are correct
157
+ expect(handlerContent).toMatch(
158
+ /from ['"].*src\/subscribers\/deep\/processor\.js['"]/,
159
+ );
160
+ expect(handlerContent).toMatch(/from ['"].*\/env['"]/);
161
+ });
162
+
163
+ it('should handle subscribers with different timeout values', async () => {
164
+ const constructs = [
165
+ createSubscriberConstruct('quickSubscriber', ['fast.event'], 15000),
166
+ createSubscriberConstruct('slowSubscriber', ['slow.event'], 300000),
167
+ ];
168
+
169
+ const subscriberInfos = await generator.build(
170
+ context,
171
+ constructs,
172
+ outputDir,
173
+ );
174
+
175
+ expect(subscriberInfos[0].timeout).toBe(15000);
176
+ expect(subscriberInfos[1].timeout).toBe(300000);
177
+ });
178
+
179
+ it('should handle subscribers with no subscribed events', async () => {
180
+ const subscriber = new SubscriberBuilder()
181
+ .timeout(30000)
182
+ .handle(async ({ events, logger }) => {
183
+ logger.info({ eventCount: events.length }, 'Processing all events');
184
+ });
185
+
186
+ const construct: GeneratedConstruct<
187
+ Subscriber<any, any, any, any, any, any>
188
+ > = {
189
+ key: 'catchAllSubscriber',
190
+ name: 'catch-all-subscriber',
191
+ construct: subscriber,
192
+ path: {
193
+ absolute: join(tempDir, 'catchAllSubscriber.ts'),
194
+ relative: 'catchAllSubscriber.ts',
195
+ },
196
+ };
197
+
198
+ const subscriberInfos = await generator.build(
199
+ context,
200
+ [construct],
201
+ outputDir,
202
+ );
203
+
204
+ expect(subscriberInfos[0].subscribedEvents).toEqual([]);
205
+ });
206
+
207
+ it('should handle subscribers with multiple event types', async () => {
208
+ const constructs = [
209
+ createSubscriberConstruct('multiEventSubscriber', [
210
+ 'user.created',
211
+ 'user.updated',
212
+ 'user.deleted',
213
+ 'order.placed',
214
+ ]),
215
+ ];
216
+
217
+ const subscriberInfos = await generator.build(
218
+ context,
219
+ constructs,
220
+ outputDir,
221
+ );
222
+
223
+ expect(subscriberInfos[0].subscribedEvents).toEqual([
224
+ 'user.created',
225
+ 'user.updated',
226
+ 'user.deleted',
227
+ 'order.placed',
228
+ ]);
229
+ });
230
+
231
+ it('should log generation progress', async () => {
232
+ const logSpy = vi.spyOn(console, 'log');
233
+
234
+ const constructs = [
235
+ createSubscriberConstruct('testSubscriber', ['test.event']),
236
+ ];
237
+
238
+ await generator.build(context, constructs, outputDir);
239
+
240
+ expect(logSpy).toHaveBeenCalledWith(
241
+ 'Generated subscriber handler: testSubscriber',
242
+ );
243
+
244
+ logSpy.mockRestore();
245
+ });
246
+
247
+ it('should return empty array for empty constructs', async () => {
248
+ const subscriberInfos = await generator.build(context, [], outputDir);
249
+ expect(subscriberInfos).toEqual([]);
250
+ });
251
+
252
+ it('should handle subscribers with custom environment parser patterns', async () => {
253
+ const customContext = {
254
+ ...context,
255
+ envParserImportPattern: '{ customParser as envParser }',
256
+ };
257
+
258
+ const constructs = [
259
+ createSubscriberConstruct('customSubscriber', ['custom.event']),
260
+ ];
261
+
262
+ await generator.build(customContext, constructs, outputDir);
263
+
264
+ const handlerPath = join(outputDir, 'subscribers', 'customSubscriber.ts');
265
+ const handlerContent = await readFile(handlerPath, 'utf-8');
266
+
267
+ expect(handlerContent).toContain('import { customParser as envParser }');
268
+ });
269
+
270
+ it('should create subscribers directory if it does not exist', async () => {
271
+ const constructs = [
272
+ createSubscriberConstruct('firstSubscriber', ['first.event']),
273
+ ];
274
+
275
+ // outputDir does not exist yet
276
+ await generator.build(context, constructs, outputDir);
277
+
278
+ const subscribersDir = join(outputDir, 'subscribers');
279
+ const handlerPath = join(subscribersDir, 'firstSubscriber.ts');
280
+
281
+ // Should be able to read the file, meaning the directory was created
282
+ const content = await readFile(handlerPath, 'utf-8');
283
+ expect(content).toContain('AWSLambdaSubscriber');
284
+ });
285
+
286
+ it('should handle exported subscriber with custom name', async () => {
287
+ const subscriber = new SubscriberBuilder()
288
+ .subscribe(['custom.event'] as any)
289
+ .handle(async ({ events, logger }) => {
290
+ logger.info({ eventCount: events.length }, 'Processing events');
291
+ });
292
+
293
+ const construct: GeneratedConstruct<
294
+ Subscriber<any, any, any, any, any, any>
295
+ > = {
296
+ key: 'myCustomSubscriberName',
297
+ name: 'custom-name',
298
+ construct: subscriber,
299
+ path: {
300
+ absolute: join(tempDir, 'subscriber.ts'),
301
+ relative: 'subscriber.ts',
302
+ },
303
+ };
304
+
305
+ await generator.build(context, [construct], outputDir);
306
+
307
+ const handlerPath = join(
308
+ outputDir,
309
+ 'subscribers',
310
+ 'myCustomSubscriberName.ts',
311
+ );
312
+ const handlerContent = await readFile(handlerPath, 'utf-8');
313
+
314
+ expect(handlerContent).toContain(
315
+ 'import { myCustomSubscriberName } from',
316
+ );
317
+ expect(handlerContent).toContain(
318
+ 'new AWSLambdaSubscriber(envParser, myCustomSubscriberName)',
319
+ );
320
+ });
321
+
322
+ it('should generate handler files that can be imported', async () => {
323
+ const constructs = [
324
+ createSubscriberConstruct('validSubscriber', ['valid.event']),
325
+ ];
326
+
327
+ await generator.build(context, constructs, outputDir);
328
+
329
+ const handlerPath = join(outputDir, 'subscribers', 'validSubscriber.ts');
330
+ const handlerContent = await readFile(handlerPath, 'utf-8');
331
+
332
+ // Check that the generated file has proper structure
333
+ expect(handlerContent).toContain(
334
+ "import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws'",
335
+ );
336
+ expect(handlerContent).toContain(
337
+ 'export const handler = adapter.handler',
338
+ );
339
+ });
340
+ });
341
+ });
@@ -0,0 +1,9 @@
1
+ export { CronGenerator } from './CronGenerator';
2
+ export { EndpointGenerator } from './EndpointGenerator';
3
+ export { FunctionGenerator } from './FunctionGenerator';
4
+ export { SubscriberGenerator } from './SubscriberGenerator';
5
+ export {
6
+ ConstructGenerator,
7
+ type GeneratedConstruct,
8
+ type GeneratorOptions,
9
+ } from './Generator';
package/src/index.ts CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import pkg from '../package.json' assert { type: 'json' };
5
- import { buildCommand } from './build.ts';
5
+ import { buildCommand } from './build/index.ts';
6
6
  import { generateReactQueryCommand } from './openapi-react-query.ts';
7
7
  import { openapiCommand } from './openapi.ts';
8
- import type { Provider } from './types.ts';
8
+ import type { LegacyProvider, MainProvider } from './types.ts';
9
9
 
10
10
  const program = new Command();
11
11
 
@@ -17,34 +17,69 @@ program
17
17
 
18
18
  program
19
19
  .command('build')
20
- .description('Build API handlers from endpoints')
20
+ .description('Build handlers from endpoints, functions, and crons')
21
+ .option(
22
+ '--provider <provider>',
23
+ 'Target provider for generated handlers (aws, server)',
24
+ )
21
25
  .option(
22
26
  '--providers <providers>',
23
- 'Target providers for generated handlers (comma-separated)',
24
- 'aws-apigatewayv1',
27
+ '[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)',
25
28
  )
26
29
  .option(
27
30
  '--enable-openapi',
28
31
  'Enable OpenAPI documentation generation for server builds',
29
32
  )
30
- .action(async (options: { providers: string; enableOpenapi?: boolean }) => {
31
- try {
32
- const globalOptions = program.opts();
33
- if (globalOptions.cwd) {
34
- process.chdir(globalOptions.cwd);
33
+ .action(
34
+ async (options: {
35
+ provider?: string;
36
+ providers?: string;
37
+ enableOpenapi?: boolean;
38
+ }) => {
39
+ try {
40
+ const globalOptions = program.opts();
41
+ if (globalOptions.cwd) {
42
+ process.chdir(globalOptions.cwd);
43
+ }
44
+
45
+ // Handle new single provider option
46
+ if (options.provider) {
47
+ if (!['aws', 'server'].includes(options.provider)) {
48
+ console.error(
49
+ `Invalid provider: ${options.provider}. Must be 'aws' or 'server'.`,
50
+ );
51
+ process.exit(1);
52
+ }
53
+ await buildCommand({
54
+ provider: options.provider as MainProvider,
55
+ enableOpenApi: options.enableOpenapi || false,
56
+ });
57
+ }
58
+ // Handle legacy providers option
59
+ else if (options.providers) {
60
+ console.warn(
61
+ '⚠️ --providers flag is deprecated. Use --provider instead.',
62
+ );
63
+ const providerList = [
64
+ ...new Set(options.providers.split(',').map((p) => p.trim())),
65
+ ] as LegacyProvider[];
66
+ await buildCommand({
67
+ providers: providerList,
68
+ enableOpenApi: options.enableOpenapi || false,
69
+ });
70
+ }
71
+ // Default to config-driven build
72
+ else {
73
+ await buildCommand({
74
+ enableOpenApi: options.enableOpenapi || false,
75
+ });
76
+ }
77
+ } catch (error) {
78
+ console.error('Build failed:', (error as Error).message);
79
+ process.exit(1);
35
80
  }
36
- const providerList = [
37
- ...new Set(options.providers.split(',').map((p) => p.trim())),
38
- ] as Provider[];
39
- await buildCommand({
40
- providers: providerList,
41
- enableOpenApi: options.enableOpenapi || false,
42
- });
43
- } catch (error) {
44
- console.error('Build failed:', (error as Error).message);
45
- process.exit(1);
46
- }
47
- });
81
+ },
82
+ );
48
83
 
49
84
  program
50
85
  .command('cron')
@@ -63,6 +63,7 @@ export async function generateReactQueryCommand(
63
63
  logger.warn('Run: npm install -D openapi-typescript');
64
64
 
65
65
  // Generate basic types file
66
+ await mkdir(dirname(typesPath), { recursive: true });
66
67
  await writeFile(
67
68
  typesPath,
68
69
  `// Auto-generated placeholder types
@@ -185,7 +186,7 @@ function generateReactQueryCode(
185
186
  operations: OperationInfo[],
186
187
  apiName: string,
187
188
  ): string {
188
- const imports = `import { createTypedQueryClient } from '@geekmidas/api/client';
189
+ const imports = `import { createTypedQueryClient } from '@geekmidas/client';
189
190
  import type { paths } from './openapi-types';
190
191
 
191
192
  // Create typed query client
package/src/openapi.ts CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  import { mkdir, writeFile } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
- import { Endpoint } from '@geekmidas/api/server';
5
+ import { Endpoint } from '@geekmidas/constructs/endpoints';
6
6
  import { loadConfig } from './config.js';
7
- import { loadEndpoints } from './loadEndpoints.js';
7
+ import { EndpointGenerator } from './generators/EndpointGenerator.js';
8
8
 
9
9
  interface OpenAPIOptions {
10
10
  output?: string;
@@ -18,9 +18,10 @@ export async function openapiCommand(
18
18
  try {
19
19
  // Load config using existing function
20
20
  const config = await loadConfig();
21
+ const generator = new EndpointGenerator();
21
22
 
22
23
  // Load all endpoints using the refactored function
23
- const loadedEndpoints = await loadEndpoints(config.routes);
24
+ const loadedEndpoints = await generator.load(config.routes);
24
25
 
25
26
  if (loadedEndpoints.length === 0) {
26
27
  logger.log('No valid endpoints found');
@@ -28,7 +29,7 @@ export async function openapiCommand(
28
29
  }
29
30
 
30
31
  // Extract just the endpoint instances for OpenAPI generation
31
- const endpoints = loadedEndpoints.map(({ endpoint }) => endpoint);
32
+ const endpoints = loadedEndpoints.map(({ construct }) => construct);
32
33
 
33
34
  // Generate OpenAPI spec using built-in method
34
35
  const spec = await Endpoint.buildOpenApiSchema(endpoints, {
package/src/types.ts CHANGED
@@ -1,15 +1,58 @@
1
- export type Provider = 'server' | 'aws-apigatewayv1' | 'aws-apigatewayv2';
1
+ export type MainProvider = 'aws' | 'server';
2
+ export type LegacyProvider =
3
+ | 'server'
4
+ | 'aws-apigatewayv1'
5
+ | 'aws-apigatewayv2'
6
+ | 'aws-lambda';
2
7
 
3
8
  export type Routes = string | string[];
4
9
 
10
+ export interface ProviderConfig {
11
+ enabled?: boolean;
12
+ outputDir?: string;
13
+ }
14
+
15
+ export interface AWSApiGatewayConfig extends ProviderConfig {
16
+ // Additional AWS API Gateway specific options
17
+ }
18
+
19
+ export interface AWSLambdaConfig extends ProviderConfig {
20
+ // Additional AWS Lambda specific options
21
+ }
22
+
23
+ export interface ServerConfig extends ProviderConfig {
24
+ enableOpenApi?: boolean;
25
+ port?: number;
26
+ }
27
+
28
+ export interface ProvidersConfig {
29
+ aws?: {
30
+ apiGateway?: {
31
+ v1?: boolean | AWSApiGatewayConfig;
32
+ v2?: boolean | AWSApiGatewayConfig;
33
+ };
34
+ lambda?: {
35
+ functions?: boolean | AWSLambdaConfig;
36
+ crons?: boolean | AWSLambdaConfig;
37
+ };
38
+ };
39
+ server?: boolean | ServerConfig;
40
+ }
41
+
5
42
  export interface GkmConfig {
6
43
  routes: Routes;
44
+ functions?: Routes;
45
+ crons?: Routes;
46
+ subscribers?: Routes;
7
47
  envParser: string;
8
48
  logger: string;
49
+ providers?: ProvidersConfig;
9
50
  }
10
51
 
11
52
  export interface BuildOptions {
12
- providers: Provider[];
53
+ provider?: MainProvider;
54
+ // Legacy support - will be deprecated
55
+ providers?: LegacyProvider[];
13
56
  enableOpenApi?: boolean;
14
57
  }
15
58
 
@@ -17,8 +60,54 @@ export interface RouteInfo {
17
60
  path: string;
18
61
  method: string;
19
62
  handler: string;
63
+ environment?: string[];
64
+ }
65
+
66
+ export interface FunctionInfo {
67
+ name: string;
68
+ handler: string;
69
+ timeout?: number;
70
+ memorySize?: number;
71
+ environment?: string[];
72
+ }
73
+
74
+ export interface CronInfo {
75
+ name: string;
76
+ handler: string;
77
+ schedule: string;
78
+ timeout?: number;
79
+ memorySize?: number;
80
+ environment?: string[];
81
+ }
82
+
83
+ export interface SubscriberInfo {
84
+ name: string;
85
+ handler: string;
86
+ subscribedEvents: string[];
87
+ timeout?: number;
88
+ memorySize?: number;
89
+ environment?: string[];
20
90
  }
21
91
 
22
92
  export interface RoutesManifest {
23
93
  routes: RouteInfo[];
24
94
  }
95
+
96
+ export interface FunctionsManifest {
97
+ functions: FunctionInfo[];
98
+ }
99
+
100
+ export interface CronsManifest {
101
+ crons: CronInfo[];
102
+ }
103
+
104
+ export interface SubscribersManifest {
105
+ subscribers: SubscriberInfo[];
106
+ }
107
+
108
+ export interface BuildManifest {
109
+ routes: RouteInfo[];
110
+ functions: FunctionInfo[];
111
+ crons: CronInfo[];
112
+ subscribers: SubscriberInfo[];
113
+ }