@geekmidas/cli 0.1.0 → 0.2.1

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-CB-NHtZW.cjs +205 -0
  19. package/dist/SubscriberGenerator-CB-NHtZW.cjs.map +1 -0
  20. package/dist/SubscriberGenerator-Cuu4co3-.mjs +199 -0
  21. package/dist/SubscriberGenerator-Cuu4co3-.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-Ajg356_5.cjs +89 -0
  28. package/dist/build-Ajg356_5.cjs.map +1 -0
  29. package/dist/build-zpABVsc0.mjs +83 -0
  30. package/dist/build-zpABVsc0.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 +274 -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 +392 -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
@@ -1,15 +1,25 @@
1
1
  import { mkdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import type { Cron, Function } from '@geekmidas/api/constructs';
4
- import type { Endpoint } from '@geekmidas/api/server';
3
+ import type { Cron } from '@geekmidas/constructs/crons';
4
+ import type { Endpoint } from '@geekmidas/constructs/endpoints';
5
+ import type { Function } from '@geekmidas/constructs/functions';
6
+ import type { Subscriber } from '@geekmidas/constructs/subscribers';
5
7
  import { loadConfig } from '../config';
6
8
  import {
7
9
  CronGenerator,
8
10
  EndpointGenerator,
9
11
  FunctionGenerator,
10
12
  type GeneratedConstruct,
13
+ SubscriberGenerator,
11
14
  } from '../generators';
12
- import type { BuildOptions, LegacyProvider } from '../types';
15
+ import type {
16
+ BuildOptions,
17
+ CronInfo,
18
+ FunctionInfo,
19
+ LegacyProvider,
20
+ RouteInfo,
21
+ SubscriberInfo,
22
+ } from '../types';
13
23
  import { generateManifests } from './manifests';
14
24
  import { resolveProviders } from './providerResolver';
15
25
  import type { BuildContext } from './types';
@@ -30,6 +40,9 @@ export async function buildCommand(options: BuildOptions): Promise<void> {
30
40
  if (config.crons) {
31
41
  logger.log(`Loading crons from: ${config.crons}`);
32
42
  }
43
+ if (config.subscribers) {
44
+ logger.log(`Loading subscribers from: ${config.subscribers}`);
45
+ }
33
46
  logger.log(`Using envParser: ${config.envParser}`);
34
47
 
35
48
  // Parse envParser configuration
@@ -59,29 +72,40 @@ export async function buildCommand(options: BuildOptions): Promise<void> {
59
72
  const endpointGenerator = new EndpointGenerator();
60
73
  const functionGenerator = new FunctionGenerator();
61
74
  const cronGenerator = new CronGenerator();
75
+ const subscriberGenerator = new SubscriberGenerator();
62
76
 
63
77
  // Load all constructs in parallel
64
- const [allEndpoints, allFunctions, allCrons] = await Promise.all([
65
- endpointGenerator.load(config.routes),
66
- config.functions ? functionGenerator.load(config.functions) : [],
67
- config.crons ? cronGenerator.load(config.crons) : [],
68
- ]);
78
+ const [allEndpoints, allFunctions, allCrons, allSubscribers] =
79
+ await Promise.all([
80
+ endpointGenerator.load(config.routes),
81
+ config.functions ? functionGenerator.load(config.functions) : [],
82
+ config.crons ? cronGenerator.load(config.crons) : [],
83
+ config.subscribers ? subscriberGenerator.load(config.subscribers) : [],
84
+ ]);
69
85
 
70
86
  logger.log(`Found ${allEndpoints.length} endpoints`);
71
87
  logger.log(`Found ${allFunctions.length} functions`);
72
88
  logger.log(`Found ${allCrons.length} crons`);
89
+ logger.log(`Found ${allSubscribers.length} subscribers`);
73
90
 
74
91
  if (
75
92
  allEndpoints.length === 0 &&
76
93
  allFunctions.length === 0 &&
77
- allCrons.length === 0
94
+ allCrons.length === 0 &&
95
+ allSubscribers.length === 0
78
96
  ) {
79
- logger.log('No endpoints, functions, or crons found to process');
97
+ logger.log(
98
+ 'No endpoints, functions, crons, or subscribers found to process',
99
+ );
80
100
  return;
81
101
  }
82
102
 
83
- // Build for each provider in parallel
84
- await Promise.all(
103
+ // Ensure .gkm directory exists
104
+ const rootOutputDir = join(process.cwd(), '.gkm');
105
+ await mkdir(rootOutputDir, { recursive: true });
106
+
107
+ // Collect all build results from each provider
108
+ const allBuildResults = await Promise.all(
85
109
  resolved.providers.map((provider) =>
86
110
  buildForProvider(
87
111
  provider,
@@ -89,13 +113,41 @@ export async function buildCommand(options: BuildOptions): Promise<void> {
89
113
  endpointGenerator,
90
114
  functionGenerator,
91
115
  cronGenerator,
116
+ subscriberGenerator,
92
117
  allEndpoints,
93
118
  allFunctions,
94
119
  allCrons,
120
+ allSubscribers,
95
121
  resolved.enableOpenApi,
96
122
  ),
97
123
  ),
98
124
  );
125
+
126
+ // Aggregate all routes, functions, crons, and subscribers from all providers
127
+ const aggregatedRoutes = allBuildResults.flatMap((result) => result.routes);
128
+ const aggregatedFunctions = allBuildResults.flatMap(
129
+ (result) => result.functions,
130
+ );
131
+ const aggregatedCrons = allBuildResults.flatMap((result) => result.crons);
132
+ const aggregatedSubscribers = allBuildResults.flatMap(
133
+ (result) => result.subscribers,
134
+ );
135
+
136
+ // Generate single manifest at root .gkm directory
137
+ await generateManifests(
138
+ rootOutputDir,
139
+ aggregatedRoutes,
140
+ aggregatedFunctions,
141
+ aggregatedCrons,
142
+ aggregatedSubscribers,
143
+ );
144
+ }
145
+
146
+ interface BuildResult {
147
+ routes: RouteInfo[];
148
+ functions: FunctionInfo[];
149
+ crons: CronInfo[];
150
+ subscribers: SubscriberInfo[];
99
151
  }
100
152
 
101
153
  async function buildForProvider(
@@ -104,11 +156,13 @@ async function buildForProvider(
104
156
  endpointGenerator: EndpointGenerator,
105
157
  functionGenerator: FunctionGenerator,
106
158
  cronGenerator: CronGenerator,
159
+ subscriberGenerator: SubscriberGenerator,
107
160
  endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],
108
161
  functions: GeneratedConstruct<Function<any, any, any, any>>[],
109
162
  crons: GeneratedConstruct<Cron<any, any, any, any>>[],
163
+ subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],
110
164
  enableOpenApi: boolean,
111
- ): Promise<void> {
165
+ ): Promise<BuildResult> {
112
166
  const outputDir = join(process.cwd(), '.gkm', provider);
113
167
 
114
168
  // Ensure output directory exists
@@ -117,20 +171,27 @@ async function buildForProvider(
117
171
  logger.log(`\nGenerating handlers for provider: ${provider}`);
118
172
 
119
173
  // Build all constructs in parallel
120
- const [routes, functionInfos, cronInfos] = await Promise.all([
121
- endpointGenerator.build(context, endpoints, outputDir, {
122
- provider,
123
- enableOpenApi,
124
- }),
125
- functionGenerator.build(context, functions, outputDir, { provider }),
126
- cronGenerator.build(context, crons, outputDir, { provider }),
127
- ]);
128
-
129
- // Generate manifests
130
- await generateManifests(
131
- outputDir,
132
- routes,
133
- functionInfos,
134
- cronInfos,
174
+ const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(
175
+ [
176
+ endpointGenerator.build(context, endpoints, outputDir, {
177
+ provider,
178
+ enableOpenApi,
179
+ }),
180
+ functionGenerator.build(context, functions, outputDir, { provider }),
181
+ cronGenerator.build(context, crons, outputDir, { provider }),
182
+ subscriberGenerator.build(context, subscribers, outputDir, { provider }),
183
+ ],
135
184
  );
185
+
186
+ logger.log(
187
+ `Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,
188
+ );
189
+
190
+ // Return build results instead of generating manifest here
191
+ return {
192
+ routes,
193
+ functions: functionInfos,
194
+ crons: cronInfos,
195
+ subscribers: subscriberInfos,
196
+ };
136
197
  }
@@ -5,6 +5,7 @@ import type {
5
5
  CronInfo,
6
6
  FunctionInfo,
7
7
  RouteInfo,
8
+ SubscriberInfo,
8
9
  } from '../types';
9
10
 
10
11
  const logger = console;
@@ -14,19 +15,21 @@ export async function generateManifests(
14
15
  routes: RouteInfo[],
15
16
  functions: FunctionInfo[],
16
17
  crons: CronInfo[],
18
+ subscribers: SubscriberInfo[],
17
19
  ): Promise<void> {
18
20
  // Generate unified manifest for all providers
19
21
  const manifest: BuildManifest = {
20
22
  routes,
21
23
  functions,
22
24
  crons,
25
+ subscribers,
23
26
  };
24
27
 
25
28
  const manifestPath = join(outputDir, 'manifest.json');
26
29
  await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
27
30
 
28
31
  logger.log(
29
- `Generated ${routes.length} routes, ${functions.length} functions, ${crons.length} crons in ${relative(process.cwd(), outputDir)}`,
32
+ `\nGenerated unified manifest with ${routes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,
30
33
  );
31
34
  logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
32
35
  }
@@ -1,5 +1,5 @@
1
- import type { Cron, Function } from '@geekmidas/api/constructs';
2
- import type { Endpoint } from '@geekmidas/api/server';
1
+ import type { Cron, Function } from '@geekmidas/constructs';
2
+ import type { Endpoint } from '@geekmidas/constructs';
3
3
 
4
4
  import type { CronInfo, FunctionInfo, RouteInfo } from '../types';
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join, relative } from 'node:path';
3
- import { Cron } from '@geekmidas/api/constructs';
3
+ import { Cron } from '@geekmidas/constructs/crons';
4
4
  import type { BuildContext } from '../build/types';
5
5
  import type { CronInfo } from '../types';
6
6
  import {
@@ -48,6 +48,7 @@ export class CronGenerator extends ConstructGenerator<
48
48
  ),
49
49
  schedule: construct.schedule || 'rate(1 hour)',
50
50
  timeout: construct.timeout,
51
+ environment: await construct.getEnvironment(),
51
52
  });
52
53
 
53
54
  logger.log(`Generated cron handler: ${key}`);
@@ -81,7 +82,7 @@ export class CronGenerator extends ConstructGenerator<
81
82
  context.loggerPath,
82
83
  );
83
84
 
84
- const content = `import { AWSScheduledFunction } from '@geekmidas/api/aws-lambda';
85
+ const content = `import { AWSScheduledFunction } from '@geekmidas/constructs/crons';
85
86
  import { ${exportName} } from '${importPath}';
86
87
  import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
87
88
  import ${context.loggerImportPattern} from '${relativeLoggerPath}';
@@ -1,6 +1,6 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join, relative } from 'node:path';
3
- import { Endpoint } from '@geekmidas/api/server';
3
+ import { Endpoint } from '@geekmidas/constructs/endpoints';
4
4
  import type { BuildContext } from '../build/types';
5
5
  import type { LegacyProvider, RouteInfo } from '../types';
6
6
  import {
@@ -33,22 +33,18 @@ export class EndpointGenerator extends ConstructGenerator<
33
33
  }
34
34
 
35
35
  if (provider === 'server') {
36
- // Generate single server file with all endpoints
37
- const serverFile = await this.generateServerFile(
38
- outputDir,
39
- constructs,
40
- context,
41
- enableOpenApi,
42
- );
36
+ // Generate endpoints.ts and app.ts
37
+ await this.generateEndpointsFile(outputDir, constructs, context);
38
+ const appFile = await this.generateAppFile(outputDir, context);
43
39
 
44
40
  routes.push({
45
41
  path: '*',
46
42
  method: 'ALL',
47
- handler: relative(process.cwd(), serverFile),
43
+ handler: relative(process.cwd(), appFile),
48
44
  });
49
45
 
50
46
  logger.log(
51
- `Generated server app with ${constructs.length} endpoints${enableOpenApi ? ' (OpenAPI enabled)' : ''}`,
47
+ `Generated server with ${constructs.length} endpoints${enableOpenApi ? ' (OpenAPI enabled)' : ''}`,
52
48
  );
53
49
  } else if (provider === 'aws-lambda') {
54
50
  // For aws-lambda, create routes subdirectory
@@ -73,6 +69,7 @@ export class EndpointGenerator extends ConstructGenerator<
73
69
  /\.ts$/,
74
70
  '.handler',
75
71
  ),
72
+ environment: await construct.getEnvironment(),
76
73
  };
77
74
 
78
75
  routes.push(routeInfo);
@@ -99,6 +96,7 @@ export class EndpointGenerator extends ConstructGenerator<
99
96
  /\.ts$/,
100
97
  '.handler',
101
98
  ),
99
+ environment: await construct.getEnvironment(),
102
100
  };
103
101
 
104
102
  routes.push(routeInfo);
@@ -160,20 +158,19 @@ export class EndpointGenerator extends ConstructGenerator<
160
158
  return handlerPath;
161
159
  }
162
160
 
163
- private async generateServerFile(
161
+ private async generateEndpointsFile(
164
162
  outputDir: string,
165
163
  endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],
166
164
  context: BuildContext,
167
- enableOpenApi: boolean,
168
165
  ): Promise<string> {
169
- const serverFileName = 'app.ts';
170
- const serverPath = join(outputDir, serverFileName);
166
+ const endpointsFileName = 'endpoints.ts';
167
+ const endpointsPath = join(outputDir, endpointsFileName);
171
168
 
172
169
  // Group imports by file
173
170
  const importsByFile = new Map<string, string[]>();
174
171
 
175
172
  for (const { path, key } of endpoints) {
176
- const relativePath = relative(dirname(serverPath), path.relative);
173
+ const relativePath = relative(dirname(endpointsPath), path.relative);
177
174
  const importPath = relativePath.replace(/\.ts$/, '.js');
178
175
 
179
176
  if (!importsByFile.has(importPath)) {
@@ -182,15 +179,6 @@ export class EndpointGenerator extends ConstructGenerator<
182
179
  importsByFile.get(importPath)!.push(key);
183
180
  }
184
181
 
185
- const relativeEnvParserPath = relative(
186
- dirname(serverPath),
187
- context.envParserPath,
188
- );
189
- const relativeLoggerPath = relative(
190
- dirname(serverPath),
191
- context.loggerPath,
192
- );
193
-
194
182
  // Generate import statements
195
183
  const imports = Array.from(importsByFile.entries())
196
184
  .map(
@@ -201,21 +189,24 @@ export class EndpointGenerator extends ConstructGenerator<
201
189
 
202
190
  const allExportNames = endpoints.map(({ key }) => key);
203
191
 
204
- const content = `import { HonoEndpoint } from '@geekmidas/api/hono';
205
- import { Endpoint } from '@geekmidas/api/server';
206
- import { ServiceDiscovery } from '@geekmidas/api/services';
207
- import { Hono } from 'hono';
208
- import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
209
- import ${context.loggerImportPattern} from '${relativeLoggerPath}';
192
+ const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
193
+ import type { Logger } from '@geekmidas/logger';
194
+ import { HonoEndpoint } from '@geekmidas/constructs/hono';
195
+ import { Endpoint } from '@geekmidas/constructs/endpoints';
196
+ import { ServiceDiscovery } from '@geekmidas/services';
197
+ import type { Hono } from 'hono';
210
198
  ${imports}
211
199
 
212
- export function createApp(app?: Hono, enableOpenApi: boolean = ${enableOpenApi}): Hono {
213
- const honoApp = app || new Hono();
214
-
215
- const endpoints: Endpoint<any, any, any, any, any, any, any>[] = [
216
- ${allExportNames.join(',\n ')}
217
- ];
200
+ const endpoints: Endpoint<any, any, any, any, any, any, any, any>[] = [
201
+ ${allExportNames.join(',\n ')}
202
+ ];
218
203
 
204
+ export function setupEndpoints(
205
+ app: Hono,
206
+ envParser: EnvironmentParser<any>,
207
+ logger: Logger,
208
+ enableOpenApi: boolean = true,
209
+ ): void {
219
210
  const serviceDiscovery = ServiceDiscovery.getInstance(
220
211
  logger,
221
212
  envParser
@@ -231,18 +222,126 @@ export function createApp(app?: Hono, enableOpenApi: boolean = ${enableOpenApi})
231
222
  }
232
223
  } : { docsPath: false };
233
224
 
234
- HonoEndpoint.addRoutes(endpoints, serviceDiscovery, honoApp, openApiOptions);
225
+ HonoEndpoint.addRoutes(endpoints, serviceDiscovery, app, openApiOptions);
226
+ }
227
+ `;
228
+
229
+ await writeFile(endpointsPath, content);
230
+
231
+ return endpointsPath;
232
+ }
233
+
234
+ private async generateAppFile(
235
+ outputDir: string,
236
+ context: BuildContext,
237
+ ): Promise<string> {
238
+ const appFileName = 'app.ts';
239
+ const appPath = join(outputDir, appFileName);
235
240
 
236
- return honoApp;
241
+ const relativeLoggerPath = relative(dirname(appPath), context.loggerPath);
242
+
243
+ const relativeEnvParserPath = relative(
244
+ dirname(appPath),
245
+ context.envParserPath,
246
+ );
247
+
248
+ const content = `/**
249
+ * Generated server application
250
+ *
251
+ * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY
252
+ * The subscriber polling mechanism is not production-ready.
253
+ * For production, use AWS Lambda with SQS/SNS event sources.
254
+ */
255
+ import { Hono } from 'hono';
256
+ import type { Hono as HonoType } from 'hono';
257
+ import { setupEndpoints } from './endpoints.js';
258
+ import { setupSubscribers } from './subscribers.js';
259
+ import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
260
+ import ${context.loggerImportPattern} from '${relativeLoggerPath}';
261
+
262
+ export interface ServerApp {
263
+ app: HonoType;
264
+ start: (options?: {
265
+ port?: number;
266
+ serve: (app: HonoType, port: number) => void | Promise<void>;
267
+ }) => Promise<void>;
268
+ }
269
+
270
+ /**
271
+ * Create and configure the Hono application
272
+ *
273
+ * @param app - Optional Hono app instance to configure (creates new one if not provided)
274
+ * @param enableOpenApi - Enable OpenAPI documentation (default: true)
275
+ * @returns Server app with configured Hono app and start function
276
+ *
277
+ * @example
278
+ * // With Bun
279
+ * import { createApp } from './.gkm/server/app.js';
280
+ *
281
+ * const { app, start } = createApp();
282
+ *
283
+ * await start({
284
+ * port: 3000,
285
+ * serve: (app, port) => {
286
+ * Bun.serve({ port, fetch: app.fetch });
287
+ * }
288
+ * });
289
+ *
290
+ * @example
291
+ * // With Node.js (using @hono/node-server)
292
+ * import { serve } from '@hono/node-server';
293
+ * import { createApp } from './.gkm/server/app.js';
294
+ *
295
+ * const { app, start } = createApp();
296
+ *
297
+ * await start({
298
+ * port: 3000,
299
+ * serve: (app, port) => {
300
+ * serve({ fetch: app.fetch, port });
301
+ * }
302
+ * });
303
+ */
304
+ export function createApp(app?: HonoType, enableOpenApi: boolean = true): ServerApp {
305
+ const honoApp = app || new Hono();
306
+
307
+ // Setup HTTP endpoints
308
+ setupEndpoints(honoApp, envParser, logger, enableOpenApi);
309
+
310
+ return {
311
+ app: honoApp,
312
+ async start(options) {
313
+ if (!options?.serve) {
314
+ throw new Error(
315
+ 'serve function is required. Pass a serve function for your runtime:\\n' +
316
+ ' - Bun: (app, port) => Bun.serve({ port, fetch: app.fetch })\\n' +
317
+ ' - Node: (app, port) => serve({ fetch: app.fetch, port })'
318
+ );
319
+ }
320
+
321
+ const port = options.port ?? 3000;
322
+
323
+ // Start subscribers in background (non-blocking, local development only)
324
+ await setupSubscribers(envParser, logger).catch((error) => {
325
+ logger.error({ error }, 'Failed to start subscribers');
326
+ });
327
+
328
+ logger.info({ port }, 'Starting server');
329
+
330
+ // Start HTTP server using provided serve function
331
+ await options.serve(honoApp, port);
332
+
333
+ logger.info({ port }, 'Server started');
334
+ }
335
+ };
237
336
  }
238
337
 
239
338
  // Default export for convenience
240
339
  export default createApp;
241
340
  `;
242
341
 
243
- await writeFile(serverPath, content);
342
+ await writeFile(appPath, content);
244
343
 
245
- return serverPath;
344
+ return appPath;
246
345
  }
247
346
 
248
347
  private generateAWSApiGatewayV1Handler(
@@ -251,7 +350,7 @@ export default createApp;
251
350
  envParserPath: string,
252
351
  envParserImportPattern: string,
253
352
  ): string {
254
- return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/api/aws-apigateway';
353
+ return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
255
354
  import { ${exportName} } from '${importPath}';
256
355
  import ${envParserImportPattern} from '${envParserPath}';
257
356
 
@@ -267,7 +366,7 @@ export const handler = adapter.handler;
267
366
  envParserPath: string,
268
367
  envParserImportPattern: string,
269
368
  ): string {
270
- return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/api/aws-apigateway';
369
+ return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
271
370
  import { ${exportName} } from '${importPath}';
272
371
  import ${envParserImportPattern} from '${envParserPath}';
273
372
 
@@ -1,6 +1,6 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join, relative } from 'node:path';
3
- import { Function } from '@geekmidas/api/constructs';
3
+ import { Function } from '@geekmidas/constructs/functions';
4
4
  import type { BuildContext } from '../build/types';
5
5
  import type { FunctionInfo } from '../types';
6
6
  import {
@@ -51,6 +51,7 @@ export class FunctionGenerator extends ConstructGenerator<
51
51
  '.handler',
52
52
  ),
53
53
  timeout: construct.timeout,
54
+ environment: await construct.getEnvironment(),
54
55
  });
55
56
 
56
57
  logger.log(`Generated function handler: ${key}`);
@@ -80,7 +81,7 @@ export class FunctionGenerator extends ConstructGenerator<
80
81
  context.loggerPath,
81
82
  );
82
83
 
83
- const content = `import { AWSLambdaFunction } from '@geekmidas/api/aws-lambda';
84
+ const content = `import { AWSLambdaFunction } from '@geekmidas/constructs/functions';
84
85
  import { ${exportName} } from '${importPath}';
85
86
  import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
86
87
  import ${context.loggerImportPattern} from '${relativeLoggerPath}';
@@ -1,5 +1,5 @@
1
1
  import { relative } from 'path';
2
- import type { Construct } from '@geekmidas/api/constructs';
2
+ import type { Construct } from '@geekmidas/constructs';
3
3
  import fg from 'fast-glob';
4
4
  import kebabCase from 'lodash.kebabcase';
5
5
  import type { BuildContext } from '../build/types';