@geekmidas/cli 0.1.0 → 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 (146) hide show
  1. package/README.md +63 -13
  2. package/dist/{CronGenerator-Ctl4USy4.cjs → CronGenerator-1PflEYe2.cjs} +8 -7
  3. package/dist/CronGenerator-1PflEYe2.cjs.map +1 -0
  4. package/dist/{CronGenerator-ClbRcmz_.mjs → CronGenerator-DXRfHQcV.mjs} +6 -5
  5. package/dist/CronGenerator-DXRfHQcV.mjs.map +1 -0
  6. package/dist/{EndpointGenerator-Dj7AumHi.cjs → EndpointGenerator-BbGrDiCP.cjs} +134 -34
  7. package/dist/EndpointGenerator-BbGrDiCP.cjs.map +1 -0
  8. package/dist/{EndpointGenerator-uBA1ixUw.mjs → EndpointGenerator-BmZ9BxbO.mjs} +132 -32
  9. package/dist/EndpointGenerator-BmZ9BxbO.mjs.map +1 -0
  10. package/dist/{FunctionGenerator-DN681IUn.cjs → FunctionGenerator-Clw64SwQ.cjs} +8 -7
  11. package/dist/FunctionGenerator-Clw64SwQ.cjs.map +1 -0
  12. package/dist/{FunctionGenerator-crAa-JC7.mjs → FunctionGenerator-DOEB_yPh.mjs} +6 -5
  13. package/dist/FunctionGenerator-DOEB_yPh.mjs.map +1 -0
  14. package/dist/{Generator-C3tYSTQY.cjs → Generator-CDoEXCDg.cjs} +2 -2
  15. package/dist/Generator-CDoEXCDg.cjs.map +1 -0
  16. package/dist/{Generator-CDt4pB3W.mjs → Generator-UanJW0_V.mjs} +1 -1
  17. package/dist/Generator-UanJW0_V.mjs.map +1 -0
  18. package/dist/SubscriberGenerator-BfMZCVNy.cjs +204 -0
  19. package/dist/SubscriberGenerator-BfMZCVNy.cjs.map +1 -0
  20. package/dist/SubscriberGenerator-D2u00NI3.mjs +198 -0
  21. package/dist/SubscriberGenerator-D2u00NI3.mjs.map +1 -0
  22. package/dist/build/index.cjs +10 -9
  23. package/dist/build/index.mjs +8 -7
  24. package/dist/build/manifests.cjs +1 -1
  25. package/dist/build/manifests.mjs +1 -1
  26. package/dist/build/providerResolver.cjs +1 -1
  27. package/dist/build-BBhlEjf5.cjs +89 -0
  28. package/dist/build-BBhlEjf5.cjs.map +1 -0
  29. package/dist/build-kY-lG30Q.mjs +83 -0
  30. package/dist/build-kY-lG30Q.mjs.map +1 -0
  31. package/dist/{chunk-CsX-DzYB.cjs → chunk-CUT6urMc.cjs} +0 -12
  32. package/dist/{config-RcNESK0T.cjs → config-D1EpSGk6.cjs} +2 -2
  33. package/dist/{config-RcNESK0T.cjs.map → config-D1EpSGk6.cjs.map} +1 -1
  34. package/dist/{config-CXxYmz_o.mjs → config-U-mdW-7Y.mjs} +1 -1
  35. package/dist/{config-CXxYmz_o.mjs.map → config-U-mdW-7Y.mjs.map} +1 -1
  36. package/dist/config.cjs +1 -1
  37. package/dist/config.mjs +1 -1
  38. package/dist/generators/CronGenerator.cjs +2 -2
  39. package/dist/generators/CronGenerator.mjs +2 -2
  40. package/dist/generators/EndpointGenerator.cjs +2 -2
  41. package/dist/generators/EndpointGenerator.mjs +2 -2
  42. package/dist/generators/FunctionGenerator.cjs +2 -2
  43. package/dist/generators/FunctionGenerator.mjs +2 -2
  44. package/dist/generators/Generator.cjs +1 -1
  45. package/dist/generators/Generator.mjs +1 -1
  46. package/dist/generators/SubscriberGenerator.cjs +4 -0
  47. package/dist/generators/SubscriberGenerator.mjs +4 -0
  48. package/dist/generators/index.cjs +8 -6
  49. package/dist/generators/index.mjs +6 -5
  50. package/dist/index.cjs +18 -14
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.mjs +15 -11
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/{manifests-HX4z4kkz.mjs → manifests-BrJXpHrf.mjs} +5 -4
  55. package/dist/manifests-BrJXpHrf.mjs.map +1 -0
  56. package/dist/{manifests-BTtfDMX8.cjs → manifests-D0saShvH.cjs} +6 -5
  57. package/dist/manifests-D0saShvH.cjs.map +1 -0
  58. package/dist/{openapi-BivnatiC.mjs → openapi-BQx3_JbM.mjs} +4 -4
  59. package/dist/openapi-BQx3_JbM.mjs.map +1 -0
  60. package/dist/{openapi-DW-qF3oW.cjs → openapi-CMLr04cz.cjs} +6 -6
  61. package/dist/openapi-CMLr04cz.cjs.map +1 -0
  62. package/dist/{openapi-react-query-lgS7AVEz.mjs → openapi-react-query-DbrWwQzb.mjs} +3 -2
  63. package/dist/openapi-react-query-DbrWwQzb.mjs.map +1 -0
  64. package/dist/{openapi-react-query-J0BzBHhN.cjs → openapi-react-query-Dvjqx_Eo.cjs} +4 -3
  65. package/dist/openapi-react-query-Dvjqx_Eo.cjs.map +1 -0
  66. package/dist/openapi-react-query.cjs +1 -1
  67. package/dist/openapi-react-query.mjs +1 -1
  68. package/dist/openapi.cjs +4 -4
  69. package/dist/openapi.mjs +4 -4
  70. package/dist/{providerResolver-Cs-0YCaP.cjs → providerResolver-DgvzNfP4.cjs} +1 -1
  71. package/dist/{providerResolver-Cs-0YCaP.cjs.map → providerResolver-DgvzNfP4.cjs.map} +1 -1
  72. package/examples/cron-example.ts +1 -1
  73. package/examples/function-example.ts +1 -1
  74. package/examples/logger.ts +1 -1
  75. package/package.json +6 -3
  76. package/src/__tests__/openapi-react-query.spec.ts +506 -0
  77. package/src/__tests__/openapi.spec.ts +362 -0
  78. package/src/__tests__/test-helpers.ts +10 -8
  79. package/src/build/__tests__/index-new.spec.ts +41 -42
  80. package/src/build/index.ts +89 -28
  81. package/src/build/manifests.ts +4 -1
  82. package/src/build/types.ts +2 -2
  83. package/src/generators/CronGenerator.ts +3 -2
  84. package/src/generators/EndpointGenerator.ts +141 -42
  85. package/src/generators/FunctionGenerator.ts +3 -2
  86. package/src/generators/Generator.ts +1 -1
  87. package/src/generators/SubscriberGenerator.ts +271 -0
  88. package/src/generators/__tests__/CronGenerator.spec.ts +1 -1
  89. package/src/generators/__tests__/EndpointGenerator.spec.ts +33 -11
  90. package/src/generators/__tests__/FunctionGenerator.spec.ts +21 -22
  91. package/src/generators/__tests__/SubscriberGenerator.spec.ts +341 -0
  92. package/src/generators/index.ts +1 -0
  93. package/src/openapi-react-query.ts +2 -1
  94. package/src/openapi.ts +1 -1
  95. package/src/types.ts +18 -0
  96. package/dist/CronGenerator-ClbRcmz_.mjs.map +0 -1
  97. package/dist/CronGenerator-Ctl4USy4.cjs.map +0 -1
  98. package/dist/EndpointGenerator-Dj7AumHi.cjs.map +0 -1
  99. package/dist/EndpointGenerator-uBA1ixUw.mjs.map +0 -1
  100. package/dist/FunctionGenerator-DN681IUn.cjs.map +0 -1
  101. package/dist/FunctionGenerator-crAa-JC7.mjs.map +0 -1
  102. package/dist/Generator-C3tYSTQY.cjs.map +0 -1
  103. package/dist/Generator-CDt4pB3W.mjs.map +0 -1
  104. package/dist/__tests__/config.spec.cjs +0 -98
  105. package/dist/__tests__/config.spec.cjs.map +0 -1
  106. package/dist/__tests__/config.spec.mjs +0 -97
  107. package/dist/__tests__/config.spec.mjs.map +0 -1
  108. package/dist/__tests__/test-helpers.cjs +0 -14
  109. package/dist/__tests__/test-helpers.mjs +0 -4
  110. package/dist/build/__tests__/index-new.spec.cjs +0 -286
  111. package/dist/build/__tests__/index-new.spec.cjs.map +0 -1
  112. package/dist/build/__tests__/index-new.spec.mjs +0 -285
  113. package/dist/build/__tests__/index-new.spec.mjs.map +0 -1
  114. package/dist/build-BZdwxCLW.mjs +0 -64
  115. package/dist/build-BZdwxCLW.mjs.map +0 -1
  116. package/dist/build-BfQFnU5-.cjs +0 -70
  117. package/dist/build-BfQFnU5-.cjs.map +0 -1
  118. package/dist/esm-9eeZntth.mjs +0 -3777
  119. package/dist/esm-9eeZntth.mjs.map +0 -1
  120. package/dist/esm-Crmo4h9t.cjs +0 -4392
  121. package/dist/esm-Crmo4h9t.cjs.map +0 -1
  122. package/dist/esm-CsJbr7gi.mjs +0 -3
  123. package/dist/esm-w09tAC4l.cjs +0 -8
  124. package/dist/generators/__tests__/CronGenerator.spec.cjs +0 -216
  125. package/dist/generators/__tests__/CronGenerator.spec.cjs.map +0 -1
  126. package/dist/generators/__tests__/CronGenerator.spec.mjs +0 -215
  127. package/dist/generators/__tests__/CronGenerator.spec.mjs.map +0 -1
  128. package/dist/generators/__tests__/EndpointGenerator.spec.cjs +0 -182
  129. package/dist/generators/__tests__/EndpointGenerator.spec.cjs.map +0 -1
  130. package/dist/generators/__tests__/EndpointGenerator.spec.mjs +0 -181
  131. package/dist/generators/__tests__/EndpointGenerator.spec.mjs.map +0 -1
  132. package/dist/generators/__tests__/FunctionGenerator.spec.cjs +0 -152
  133. package/dist/generators/__tests__/FunctionGenerator.spec.cjs.map +0 -1
  134. package/dist/generators/__tests__/FunctionGenerator.spec.mjs +0 -151
  135. package/dist/generators/__tests__/FunctionGenerator.spec.mjs.map +0 -1
  136. package/dist/manifests-BTtfDMX8.cjs.map +0 -1
  137. package/dist/manifests-HX4z4kkz.mjs.map +0 -1
  138. package/dist/openapi-BivnatiC.mjs.map +0 -1
  139. package/dist/openapi-DW-qF3oW.cjs.map +0 -1
  140. package/dist/openapi-react-query-J0BzBHhN.cjs.map +0 -1
  141. package/dist/openapi-react-query-lgS7AVEz.mjs.map +0 -1
  142. package/dist/test-helpers-ARd8GDgx.cjs +0 -199
  143. package/dist/test-helpers-ARd8GDgx.cjs.map +0 -1
  144. package/dist/test-helpers-DdVBk23F.mjs +0 -133
  145. package/dist/test-helpers-DdVBk23F.mjs.map +0 -1
  146. /package/dist/{generators-_pY7sHy1.cjs → generators-CEKtVh81.cjs} +0 -0
@@ -0,0 +1,362 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import { openapiCommand } from '../openapi';
6
+ import {
7
+ cleanupDir,
8
+ createMockEndpointFile,
9
+ createTempDir,
10
+ createTestFile,
11
+ } from './test-helpers';
12
+
13
+ describe('OpenAPI Generation', () => {
14
+ let tempDir: string;
15
+
16
+ beforeEach(async () => {
17
+ tempDir = await createTempDir('openapi-test-');
18
+ });
19
+
20
+ afterEach(async () => {
21
+ await cleanupDir(tempDir);
22
+ vi.restoreAllMocks();
23
+ });
24
+
25
+ describe('openapiCommand', () => {
26
+ it('should generate OpenAPI spec for endpoints', async () => {
27
+ // Create endpoint file
28
+ await createMockEndpointFile(
29
+ tempDir,
30
+ 'getUser.ts',
31
+ 'getUser',
32
+ '/users/:id',
33
+ 'GET',
34
+ );
35
+
36
+ // Create config file
37
+ await createTestFile(
38
+ tempDir,
39
+ 'gkm.config.json',
40
+ JSON.stringify({
41
+ routes: [`${tempDir}/**/*.ts`],
42
+ }),
43
+ );
44
+
45
+ const outputPath = join(tempDir, 'openapi.json');
46
+
47
+ // Mock process.cwd
48
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
49
+
50
+ await openapiCommand({ output: outputPath });
51
+
52
+ // Verify file was created
53
+ expect(existsSync(outputPath)).toBe(true);
54
+
55
+ // Verify content
56
+ const content = await readFile(outputPath, 'utf-8');
57
+ const spec = JSON.parse(content);
58
+
59
+ expect(spec).toHaveProperty('openapi');
60
+ expect(spec).toHaveProperty('info');
61
+ expect(spec.info.title).toBe('API Documentation');
62
+ expect(spec).toHaveProperty('paths');
63
+ expect(Object.keys(spec.paths).length).toBeGreaterThan(0);
64
+ });
65
+
66
+ it('should handle no endpoints found', async () => {
67
+ // Create config with no matching files
68
+ await createTestFile(
69
+ tempDir,
70
+ 'gkm.config.json',
71
+ JSON.stringify({
72
+ routes: [`${tempDir}/nonexistent/**/*.ts`],
73
+ }),
74
+ );
75
+
76
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
77
+ const consoleSpy = vi.spyOn(console, 'log');
78
+
79
+ await openapiCommand({ output: join(tempDir, 'openapi.json') });
80
+
81
+ expect(consoleSpy).toHaveBeenCalledWith('No valid endpoints found');
82
+ });
83
+
84
+ it('should use default output path when not specified', async () => {
85
+ // Create endpoint file
86
+ await createMockEndpointFile(
87
+ tempDir,
88
+ 'endpoint.ts',
89
+ 'testEndpoint',
90
+ '/test',
91
+ 'GET',
92
+ );
93
+
94
+ // Create config
95
+ await createTestFile(
96
+ tempDir,
97
+ 'gkm.config.json',
98
+ JSON.stringify({
99
+ routes: [`${tempDir}/**/*.ts`],
100
+ }),
101
+ );
102
+
103
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
104
+
105
+ await openapiCommand();
106
+
107
+ // Should create openapi.json in current directory
108
+ expect(existsSync(join(tempDir, 'openapi.json'))).toBe(true);
109
+ });
110
+
111
+ it('should generate spec with multiple endpoints', async () => {
112
+ // Create multiple endpoint files
113
+ await createMockEndpointFile(
114
+ tempDir,
115
+ 'getUsers.ts',
116
+ 'getUsers',
117
+ '/users',
118
+ 'GET',
119
+ );
120
+ await createMockEndpointFile(
121
+ tempDir,
122
+ 'createUser.ts',
123
+ 'createUser',
124
+ '/users',
125
+ 'POST',
126
+ );
127
+ await createMockEndpointFile(
128
+ tempDir,
129
+ 'deleteUser.ts',
130
+ 'deleteUser',
131
+ '/users/:id',
132
+ 'DELETE',
133
+ );
134
+
135
+ // Create config
136
+ await createTestFile(
137
+ tempDir,
138
+ 'gkm.config.json',
139
+ JSON.stringify({
140
+ routes: [`${tempDir}/**/*.ts`],
141
+ }),
142
+ );
143
+
144
+ const outputPath = join(tempDir, 'openapi.json');
145
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
146
+
147
+ await openapiCommand({ output: outputPath });
148
+
149
+ const content = await readFile(outputPath, 'utf-8');
150
+ const spec = JSON.parse(content);
151
+
152
+ // Should have multiple paths
153
+ expect(Object.keys(spec.paths).length).toBeGreaterThanOrEqual(1);
154
+ });
155
+
156
+ it('should create output directory if it does not exist', async () => {
157
+ // Create endpoint file
158
+ await createMockEndpointFile(
159
+ tempDir,
160
+ 'endpoint.ts',
161
+ 'testEndpoint',
162
+ '/test',
163
+ 'GET',
164
+ );
165
+
166
+ // Create config
167
+ await createTestFile(
168
+ tempDir,
169
+ 'gkm.config.json',
170
+ JSON.stringify({
171
+ routes: [`${tempDir}/**/*.ts`],
172
+ }),
173
+ );
174
+
175
+ const outputPath = join(tempDir, 'nested', 'dir', 'openapi.json');
176
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
177
+
178
+ await openapiCommand({ output: outputPath });
179
+
180
+ expect(existsSync(outputPath)).toBe(true);
181
+ });
182
+
183
+ it('should include API metadata in spec', async () => {
184
+ // Create endpoint
185
+ await createMockEndpointFile(
186
+ tempDir,
187
+ 'endpoint.ts',
188
+ 'testEndpoint',
189
+ '/test',
190
+ 'GET',
191
+ );
192
+
193
+ // Create config
194
+ await createTestFile(
195
+ tempDir,
196
+ 'gkm.config.json',
197
+ JSON.stringify({
198
+ routes: [`${tempDir}/**/*.ts`],
199
+ }),
200
+ );
201
+
202
+ const outputPath = join(tempDir, 'openapi.json');
203
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
204
+
205
+ await openapiCommand({ output: outputPath });
206
+
207
+ const content = await readFile(outputPath, 'utf-8');
208
+ const spec = JSON.parse(content);
209
+
210
+ expect(spec.info).toEqual({
211
+ title: 'API Documentation',
212
+ version: '1.0.0',
213
+ description: 'Auto-generated API documentation from endpoints',
214
+ });
215
+ });
216
+
217
+ it('should log generation success', async () => {
218
+ // Create endpoint
219
+ await createMockEndpointFile(
220
+ tempDir,
221
+ 'endpoint.ts',
222
+ 'testEndpoint',
223
+ '/test',
224
+ 'GET',
225
+ );
226
+
227
+ // Create config
228
+ await createTestFile(
229
+ tempDir,
230
+ 'gkm.config.json',
231
+ JSON.stringify({
232
+ routes: [`${tempDir}/**/*.ts`],
233
+ }),
234
+ );
235
+
236
+ const outputPath = join(tempDir, 'openapi.json');
237
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
238
+ const consoleSpy = vi.spyOn(console, 'log');
239
+
240
+ await openapiCommand({ output: outputPath });
241
+
242
+ expect(consoleSpy).toHaveBeenCalledWith(
243
+ expect.stringContaining('OpenAPI spec generated'),
244
+ );
245
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Found'));
246
+ expect(consoleSpy).toHaveBeenCalledWith(
247
+ expect.stringContaining('endpoints'),
248
+ );
249
+ });
250
+
251
+ it('should throw error when config loading fails', async () => {
252
+ // No config file created
253
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
254
+
255
+ await expect(openapiCommand()).rejects.toThrow(
256
+ /OpenAPI generation failed/,
257
+ );
258
+ });
259
+
260
+ it('should throw error for invalid TypeScript files', async () => {
261
+ // Create invalid TS file
262
+ await createTestFile(
263
+ tempDir,
264
+ 'invalid.ts',
265
+ 'this is not valid typescript {[}]',
266
+ );
267
+
268
+ // Create config
269
+ await createTestFile(
270
+ tempDir,
271
+ 'gkm.config.json',
272
+ JSON.stringify({
273
+ routes: [`${tempDir}/**/*.ts`],
274
+ }),
275
+ );
276
+
277
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
278
+
279
+ // Should throw error for syntax errors
280
+ await expect(
281
+ openapiCommand({ output: join(tempDir, 'openapi.json') }),
282
+ ).rejects.toThrow(/OpenAPI generation failed/);
283
+ });
284
+
285
+ it('should generate valid JSON format', async () => {
286
+ // Create endpoint
287
+ await createMockEndpointFile(
288
+ tempDir,
289
+ 'endpoint.ts',
290
+ 'testEndpoint',
291
+ '/test',
292
+ 'GET',
293
+ );
294
+
295
+ // Create config
296
+ await createTestFile(
297
+ tempDir,
298
+ 'gkm.config.json',
299
+ JSON.stringify({
300
+ routes: [`${tempDir}/**/*.ts`],
301
+ }),
302
+ );
303
+
304
+ const outputPath = join(tempDir, 'openapi.json');
305
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
306
+
307
+ await openapiCommand({ output: outputPath });
308
+
309
+ const content = await readFile(outputPath, 'utf-8');
310
+
311
+ // Should be valid JSON and properly formatted
312
+ expect(() => JSON.parse(content)).not.toThrow();
313
+ expect(content).toContain('\n'); // Formatted with indentation
314
+ });
315
+
316
+ it('should handle endpoints with complex schemas', async () => {
317
+ // Create endpoint with complex schema
318
+ const complexEndpointContent = `
319
+ import { e } from '@geekmidas/constructs/endpoints';
320
+ import { z } from 'zod';
321
+
322
+ export const complexEndpoint = e
323
+ .post('/complex')
324
+ .body(z.object({
325
+ user: z.object({
326
+ name: z.string(),
327
+ email: z.string().email(),
328
+ age: z.number().optional(),
329
+ }),
330
+ tags: z.array(z.string()),
331
+ }))
332
+ .output(z.object({
333
+ id: z.string(),
334
+ status: z.enum(['active', 'inactive']),
335
+ }))
336
+ .handle(async () => ({ id: '123', status: 'active' as const }));
337
+ `;
338
+
339
+ await createTestFile(tempDir, 'complex.ts', complexEndpointContent);
340
+
341
+ // Create config
342
+ await createTestFile(
343
+ tempDir,
344
+ 'gkm.config.json',
345
+ JSON.stringify({
346
+ routes: [`${tempDir}/**/*.ts`],
347
+ }),
348
+ );
349
+
350
+ const outputPath = join(tempDir, 'openapi.json');
351
+ vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
352
+
353
+ await openapiCommand({ output: outputPath });
354
+
355
+ const content = await readFile(outputPath, 'utf-8');
356
+ const spec = JSON.parse(content);
357
+
358
+ // Should have generated schema for complex types
359
+ expect(spec.paths).toBeDefined();
360
+ });
361
+ });
362
+ });
@@ -3,10 +3,9 @@ import { tmpdir } from 'node:os';
3
3
  import { join } from 'node:path';
4
4
  import {
5
5
  CronBuilder,
6
- FunctionBuilder,
7
6
  type ScheduleExpression,
8
- } from '@geekmidas/api/constructs';
9
- import { e } from '@geekmidas/api/server';
7
+ } from '@geekmidas/constructs/crons';
8
+ import { e } from '@geekmidas/constructs/endpoints';
10
9
  import { z } from 'zod';
11
10
 
12
11
  /**
@@ -57,7 +56,7 @@ export async function createMockEndpointFile(
57
56
  method: string = 'GET',
58
57
  ): Promise<string> {
59
58
  const content = `
60
- import { e } from '@geekmidas/api/server';
59
+ import { e } from '@geekmidas/constructs/endpoints';
61
60
  import { z } from 'zod';
62
61
 
63
62
  export const ${exportName} = e
@@ -78,10 +77,10 @@ export async function createMockFunctionFile(
78
77
  timeout = 30,
79
78
  ): Promise<string> {
80
79
  const content = `
81
- import { FunctionBuilder } from '@geekmidas/api/constructs';
80
+ import { f } from '@geekmidas/constructs/functions';
82
81
  import { z } from 'zod';
83
82
 
84
- export const ${exportName} = new FunctionBuilder()
83
+ export const ${exportName} = f
85
84
  .input(z.object({ name: z.string() }))
86
85
  .output(z.object({ greeting: z.string() }))
87
86
  .timeout(${timeout})
@@ -100,7 +99,7 @@ export async function createMockCronFile(
100
99
  schedule = 'rate(1 hour)',
101
100
  ): Promise<string> {
102
101
  const content = `
103
- import { CronBuilder } from '@geekmidas/api/constructs';
102
+ import { CronBuilder } from '@geekmidas/constructs/crons';
104
103
  import { z } from 'zod';
105
104
 
106
105
  export const ${exportName} = new CronBuilder()
@@ -129,7 +128,9 @@ export function createTestFunction(timeout: number = 30) {
129
128
  builder.input(z.object({ name: z.string() }));
130
129
  builder.output(z.object({ greeting: z.string() }));
131
130
  builder.timeout(timeout);
132
- return builder.handle(async ({ input }: any) => ({ greeting: `Hello, ${input.name}!` }));
131
+ return builder.handle(async ({ input }: any) => ({
132
+ greeting: `Hello, ${input.name}!`,
133
+ }));
133
134
  }
134
135
 
135
136
  export function createTestCron(
@@ -175,4 +176,5 @@ export async function waitFor(
175
176
  }
176
177
 
177
178
  import { dirname } from 'node:path';
179
+ import { FunctionBuilder } from '@geekmidas/constructs/functions';
178
180
  import type { HttpMethod } from '../../../api/src/constructs/types';
@@ -69,9 +69,19 @@ export default {
69
69
 
70
70
  // Check that output directories were created
71
71
  const serverDir = join(dir, '.gkm', 'server');
72
- expect(await readFile(join(serverDir, 'app.ts'), 'utf-8')).toContain(
73
- 'HonoEndpoint',
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',
74
83
  );
84
+ expect(endpointsContent).toContain('HonoEndpoint');
75
85
  } finally {
76
86
  process.chdir(originalCwd);
77
87
  }
@@ -192,29 +202,38 @@ export default {
192
202
  ),
193
203
  ).toContain('AmazonApiGatewayV2Endpoint');
194
204
 
195
- // Verify unified manifests were created with all construct types
196
- const lambdaManifestPath = join(awsLambdaDir, 'manifest.json');
197
- const apiGatewayManifestPath = join(awsApiGatewayV2Dir, 'manifest.json');
198
-
199
- const lambdaManifest = JSON.parse(
200
- await readFile(lambdaManifestPath, 'utf-8'),
201
- );
202
- const apiGatewayManifest = JSON.parse(
203
- await readFile(apiGatewayManifestPath, 'utf-8'),
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'));
205
208
 
206
- // Verify Lambda manifest structure
207
- expect(lambdaManifest).toMatchObject({
209
+ // Verify manifest structure includes all routes from both providers
210
+ expect(manifest).toMatchObject({
208
211
  routes: expect.arrayContaining([
212
+ // Routes from aws-lambda provider
209
213
  expect.objectContaining({
210
214
  path: '/users',
211
215
  method: 'GET',
212
- handler: expect.stringContaining('routes/getUsersEndpoint.handler'),
216
+ handler: expect.stringContaining(
217
+ 'routes/getUsersEndpoint.handler',
218
+ ),
213
219
  }),
214
220
  expect.objectContaining({
215
221
  path: '/posts',
216
222
  method: 'POST',
217
- handler: expect.stringContaining('routes/getPostsEndpoint.handler'),
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'),
218
237
  }),
219
238
  ]),
220
239
  functions: expect.arrayContaining([
@@ -251,31 +270,10 @@ export default {
251
270
  ]),
252
271
  });
253
272
 
254
- // Verify API Gateway manifest structure
255
- expect(apiGatewayManifest).toMatchObject({
256
- routes: expect.arrayContaining([
257
- expect.objectContaining({
258
- path: '/users',
259
- method: 'GET',
260
- handler: expect.stringContaining('getUsersEndpoint.handler'),
261
- }),
262
- expect.objectContaining({
263
- path: '/posts',
264
- method: 'POST',
265
- handler: expect.stringContaining('getPostsEndpoint.handler'),
266
- }),
267
- ]),
268
- functions: [],
269
- crons: [],
270
- });
271
-
272
- // Verify counts
273
- expect(lambdaManifest.routes).toHaveLength(2);
274
- expect(lambdaManifest.functions).toHaveLength(2);
275
- expect(lambdaManifest.crons).toHaveLength(2);
276
- expect(apiGatewayManifest.routes).toHaveLength(2);
277
- expect(apiGatewayManifest.functions).toHaveLength(0);
278
- expect(apiGatewayManifest.crons).toHaveLength(0);
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);
279
277
  } finally {
280
278
  process.chdir(originalCwd);
281
279
  }
@@ -313,8 +311,9 @@ export default {
313
311
  expect(logSpy).toHaveBeenCalledWith('Found 0 endpoints');
314
312
  expect(logSpy).toHaveBeenCalledWith('Found 0 functions');
315
313
  expect(logSpy).toHaveBeenCalledWith('Found 0 crons');
314
+ expect(logSpy).toHaveBeenCalledWith('Found 0 subscribers');
316
315
  expect(logSpy).toHaveBeenCalledWith(
317
- 'No endpoints, functions, or crons found to process',
316
+ 'No endpoints, functions, crons, or subscribers found to process',
318
317
  );
319
318
  } finally {
320
319
  process.chdir(originalCwd);