@geekmidas/cli 0.9.0 → 0.12.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 +525 -0
  2. package/dist/bundler-DRXCw_YR.mjs +70 -0
  3. package/dist/bundler-DRXCw_YR.mjs.map +1 -0
  4. package/dist/bundler-WsEvH_b2.cjs +71 -0
  5. package/dist/bundler-WsEvH_b2.cjs.map +1 -0
  6. package/dist/{config-CFls09Ey.cjs → config-AmInkU7k.cjs} +10 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-Bq72aj8e.mjs → config-DYULeEv8.mjs} +6 -4
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +2 -1
  12. package/dist/config.d.cts.map +1 -0
  13. package/dist/config.d.mts +2 -1
  14. package/dist/config.d.mts.map +1 -0
  15. package/dist/config.mjs +1 -1
  16. package/dist/encryption-C8H-38Yy.mjs +42 -0
  17. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  18. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  19. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  20. package/dist/index.cjs +2125 -184
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +2143 -197
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{openapi--vOy9mo4.mjs → openapi-BfFlOBCG.mjs} +812 -49
  25. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  26. package/dist/{openapi-CHhTPief.cjs → openapi-Bt_1FDpT.cjs} +805 -42
  27. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  28. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  29. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  30. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  31. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  32. package/dist/openapi-react-query.cjs +1 -1
  33. package/dist/openapi-react-query.d.cts.map +1 -0
  34. package/dist/openapi-react-query.d.mts.map +1 -0
  35. package/dist/openapi-react-query.mjs +1 -1
  36. package/dist/openapi.cjs +2 -2
  37. package/dist/openapi.d.cts +1 -1
  38. package/dist/openapi.d.cts.map +1 -0
  39. package/dist/openapi.d.mts +1 -1
  40. package/dist/openapi.d.mts.map +1 -0
  41. package/dist/openapi.mjs +2 -2
  42. package/dist/storage-BUYQJgz7.cjs +4 -0
  43. package/dist/storage-BXoJvmv2.cjs +149 -0
  44. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  45. package/dist/storage-C9PU_30f.mjs +101 -0
  46. package/dist/storage-C9PU_30f.mjs.map +1 -0
  47. package/dist/storage-DLJAYxzJ.mjs +3 -0
  48. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  49. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  50. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  51. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  52. package/examples/cron-example.ts +27 -27
  53. package/examples/env.ts +27 -27
  54. package/examples/function-example.ts +31 -31
  55. package/examples/gkm.config.json +20 -20
  56. package/examples/gkm.config.ts +8 -8
  57. package/examples/gkm.minimal.config.json +5 -5
  58. package/examples/gkm.production.config.json +25 -25
  59. package/examples/logger.ts +2 -2
  60. package/package.json +6 -6
  61. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  62. package/src/__tests__/config.spec.ts +55 -55
  63. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  64. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  65. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  66. package/src/__tests__/openapi.spec.ts +428 -428
  67. package/src/__tests__/test-helpers.ts +77 -76
  68. package/src/auth/__tests__/credentials.spec.ts +204 -0
  69. package/src/auth/__tests__/index.spec.ts +168 -0
  70. package/src/auth/credentials.ts +187 -0
  71. package/src/auth/index.ts +226 -0
  72. package/src/build/__tests__/index-new.spec.ts +474 -474
  73. package/src/build/__tests__/manifests.spec.ts +333 -333
  74. package/src/build/bundler.ts +141 -0
  75. package/src/build/endpoint-analyzer.ts +236 -0
  76. package/src/build/handler-templates.ts +1253 -0
  77. package/src/build/index.ts +250 -179
  78. package/src/build/manifests.ts +52 -52
  79. package/src/build/providerResolver.ts +145 -145
  80. package/src/build/types.ts +64 -43
  81. package/src/config.ts +39 -37
  82. package/src/deploy/__tests__/docker.spec.ts +111 -0
  83. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  84. package/src/deploy/__tests__/init.spec.ts +662 -0
  85. package/src/deploy/docker.ts +128 -0
  86. package/src/deploy/dokploy.ts +204 -0
  87. package/src/deploy/index.ts +136 -0
  88. package/src/deploy/init.ts +484 -0
  89. package/src/deploy/types.ts +48 -0
  90. package/src/dev/__tests__/index.spec.ts +266 -266
  91. package/src/dev/index.ts +647 -593
  92. package/src/docker/__tests__/compose.spec.ts +531 -0
  93. package/src/docker/__tests__/templates.spec.ts +280 -0
  94. package/src/docker/compose.ts +273 -0
  95. package/src/docker/index.ts +230 -0
  96. package/src/docker/templates.ts +446 -0
  97. package/src/generators/CronGenerator.ts +72 -72
  98. package/src/generators/EndpointGenerator.ts +699 -398
  99. package/src/generators/FunctionGenerator.ts +84 -84
  100. package/src/generators/Generator.ts +72 -72
  101. package/src/generators/OpenApiTsGenerator.ts +589 -589
  102. package/src/generators/SubscriberGenerator.ts +124 -124
  103. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  104. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  105. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  106. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  107. package/src/generators/index.ts +4 -4
  108. package/src/index.ts +628 -206
  109. package/src/init/__tests__/generators.spec.ts +334 -334
  110. package/src/init/__tests__/init.spec.ts +332 -332
  111. package/src/init/__tests__/utils.spec.ts +89 -89
  112. package/src/init/generators/config.ts +175 -175
  113. package/src/init/generators/docker.ts +41 -41
  114. package/src/init/generators/env.ts +72 -72
  115. package/src/init/generators/index.ts +1 -1
  116. package/src/init/generators/models.ts +64 -64
  117. package/src/init/generators/monorepo.ts +161 -161
  118. package/src/init/generators/package.ts +71 -71
  119. package/src/init/generators/source.ts +6 -6
  120. package/src/init/index.ts +203 -208
  121. package/src/init/templates/api.ts +115 -115
  122. package/src/init/templates/index.ts +75 -75
  123. package/src/init/templates/minimal.ts +98 -98
  124. package/src/init/templates/serverless.ts +89 -89
  125. package/src/init/templates/worker.ts +98 -98
  126. package/src/init/utils.ts +54 -56
  127. package/src/openapi-react-query.ts +194 -194
  128. package/src/openapi.ts +63 -63
  129. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  130. package/src/secrets/__tests__/generator.spec.ts +319 -0
  131. package/src/secrets/__tests__/index.spec.ts +91 -0
  132. package/src/secrets/__tests__/storage.spec.ts +403 -0
  133. package/src/secrets/encryption.ts +91 -0
  134. package/src/secrets/generator.ts +164 -0
  135. package/src/secrets/index.ts +383 -0
  136. package/src/secrets/storage.ts +134 -0
  137. package/src/secrets/types.ts +53 -0
  138. package/src/types.ts +295 -176
  139. package/tsconfig.json +9 -0
  140. package/tsdown.config.ts +11 -8
  141. package/dist/config-Bq72aj8e.mjs.map +0 -1
  142. package/dist/config-CFls09Ey.cjs.map +0 -1
  143. package/dist/openapi--vOy9mo4.mjs.map +0 -1
  144. package/dist/openapi-CHhTPief.cjs.map +0 -1
  145. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  146. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
@@ -5,195 +5,266 @@ import type { Endpoint } from '@geekmidas/constructs/endpoints';
5
5
  import type { Function } from '@geekmidas/constructs/functions';
6
6
  import type { Subscriber } from '@geekmidas/constructs/subscribers';
7
7
  import { loadConfig, parseModuleConfig } from '../config';
8
- import { normalizeHooksConfig, normalizeTelescopeConfig } from '../dev';
9
8
  import {
10
- CronGenerator,
11
- EndpointGenerator,
12
- FunctionGenerator,
13
- type GeneratedConstruct,
14
- SubscriberGenerator,
9
+ getProductionConfigFromGkm,
10
+ normalizeHooksConfig,
11
+ normalizeProductionConfig,
12
+ normalizeStudioConfig,
13
+ normalizeTelescopeConfig,
14
+ } from '../dev';
15
+ import {
16
+ CronGenerator,
17
+ EndpointGenerator,
18
+ FunctionGenerator,
19
+ type GeneratedConstruct,
20
+ SubscriberGenerator,
15
21
  } from '../generators';
16
- import type { BuildOptions, LegacyProvider, RouteInfo } from '../types';
22
+ import type {
23
+ BuildOptions,
24
+ BuildResult,
25
+ LegacyProvider,
26
+ RouteInfo,
27
+ } from '../types';
17
28
  import {
18
- type ServerAppInfo,
19
- generateAwsManifest,
20
- generateServerManifest,
29
+ generateAwsManifest,
30
+ generateServerManifest,
31
+ type ServerAppInfo,
21
32
  } from './manifests';
22
33
  import { resolveProviders } from './providerResolver';
23
34
  import type { BuildContext } from './types';
24
35
 
25
36
  const logger = console;
26
37
 
27
- export async function buildCommand(options: BuildOptions): Promise<void> {
28
- const config = await loadConfig();
29
-
30
- // Resolve providers from new config format
31
- const resolved = resolveProviders(config, options);
32
-
33
- logger.log(`Building with providers: ${resolved.providers.join(', ')}`);
34
- logger.log(`Loading routes from: ${config.routes}`);
35
- if (config.functions) {
36
- logger.log(`Loading functions from: ${config.functions}`);
37
- }
38
- if (config.crons) {
39
- logger.log(`Loading crons from: ${config.crons}`);
40
- }
41
- if (config.subscribers) {
42
- logger.log(`Loading subscribers from: ${config.subscribers}`);
43
- }
44
- logger.log(`Using envParser: ${config.envParser}`);
45
-
46
- // Parse envParser and logger configuration
47
- const { path: envParserPath, importPattern: envParserImportPattern } =
48
- parseModuleConfig(config.envParser, 'envParser');
49
- const { path: loggerPath, importPattern: loggerImportPattern } =
50
- parseModuleConfig(config.logger, 'logger');
51
-
52
- // Normalize telescope configuration
53
- const telescope = normalizeTelescopeConfig(config.telescope);
54
- if (telescope) {
55
- logger.log(`🔭 Telescope enabled at ${telescope.path}`);
56
- }
57
-
58
- // Normalize hooks configuration
59
- const hooks = normalizeHooksConfig(config.hooks);
60
- if (hooks) {
61
- logger.log(`🪝 Server hooks enabled`);
62
- }
63
-
64
- const buildContext: BuildContext = {
65
- envParserPath,
66
- envParserImportPattern,
67
- loggerPath,
68
- loggerImportPattern,
69
- telescope,
70
- hooks,
71
- };
72
-
73
- // Initialize generators
74
- const endpointGenerator = new EndpointGenerator();
75
- const functionGenerator = new FunctionGenerator();
76
- const cronGenerator = new CronGenerator();
77
- const subscriberGenerator = new SubscriberGenerator();
78
-
79
- // Load all constructs in parallel
80
- const [allEndpoints, allFunctions, allCrons, allSubscribers] =
81
- await Promise.all([
82
- endpointGenerator.load(config.routes),
83
- config.functions ? functionGenerator.load(config.functions) : [],
84
- config.crons ? cronGenerator.load(config.crons) : [],
85
- config.subscribers ? subscriberGenerator.load(config.subscribers) : [],
86
- ]);
87
-
88
- logger.log(`Found ${allEndpoints.length} endpoints`);
89
- logger.log(`Found ${allFunctions.length} functions`);
90
- logger.log(`Found ${allCrons.length} crons`);
91
- logger.log(`Found ${allSubscribers.length} subscribers`);
92
-
93
- if (
94
- allEndpoints.length === 0 &&
95
- allFunctions.length === 0 &&
96
- allCrons.length === 0 &&
97
- allSubscribers.length === 0
98
- ) {
99
- logger.log(
100
- 'No endpoints, functions, crons, or subscribers found to process',
101
- );
102
- return;
103
- }
104
-
105
- // Ensure .gkm directory exists
106
- const rootOutputDir = join(process.cwd(), '.gkm');
107
- await mkdir(rootOutputDir, { recursive: true });
108
-
109
- // Build for each provider and generate per-provider manifests
110
- for (const provider of resolved.providers) {
111
- await buildForProvider(
112
- provider,
113
- buildContext,
114
- rootOutputDir,
115
- endpointGenerator,
116
- functionGenerator,
117
- cronGenerator,
118
- subscriberGenerator,
119
- allEndpoints,
120
- allFunctions,
121
- allCrons,
122
- allSubscribers,
123
- resolved.enableOpenApi,
124
- );
125
- }
38
+ export async function buildCommand(
39
+ options: BuildOptions,
40
+ ): Promise<BuildResult> {
41
+ const config = await loadConfig();
42
+
43
+ // Resolve providers from new config format
44
+ const resolved = resolveProviders(config, options);
45
+
46
+ // Normalize production configuration
47
+ const productionConfigFromGkm = getProductionConfigFromGkm(config);
48
+ const production = normalizeProductionConfig(
49
+ options.production ?? false,
50
+ productionConfigFromGkm,
51
+ );
52
+
53
+ if (production) {
54
+ logger.log(`🏭 Building for PRODUCTION`);
55
+ }
56
+
57
+ logger.log(`Building with providers: ${resolved.providers.join(', ')}`);
58
+ logger.log(`Loading routes from: ${config.routes}`);
59
+ if (config.functions) {
60
+ logger.log(`Loading functions from: ${config.functions}`);
61
+ }
62
+ if (config.crons) {
63
+ logger.log(`Loading crons from: ${config.crons}`);
64
+ }
65
+ if (config.subscribers) {
66
+ logger.log(`Loading subscribers from: ${config.subscribers}`);
67
+ }
68
+ logger.log(`Using envParser: ${config.envParser}`);
69
+
70
+ // Parse envParser and logger configuration
71
+ const { path: envParserPath, importPattern: envParserImportPattern } =
72
+ parseModuleConfig(config.envParser, 'envParser');
73
+ const { path: loggerPath, importPattern: loggerImportPattern } =
74
+ parseModuleConfig(config.logger, 'logger');
75
+
76
+ // Normalize telescope configuration (disabled in production)
77
+ const telescope = production
78
+ ? undefined
79
+ : normalizeTelescopeConfig(config.telescope);
80
+ if (telescope) {
81
+ logger.log(`🔭 Telescope enabled at ${telescope.path}`);
82
+ }
83
+
84
+ // Normalize studio configuration (disabled in production)
85
+ const studio = production ? undefined : normalizeStudioConfig(config.studio);
86
+ if (studio) {
87
+ logger.log(`🗄️ Studio enabled at ${studio.path}`);
88
+ }
89
+
90
+ // Normalize hooks configuration
91
+ const hooks = normalizeHooksConfig(config.hooks);
92
+ if (hooks) {
93
+ logger.log(`🪝 Server hooks enabled`);
94
+ }
95
+
96
+ const buildContext: BuildContext = {
97
+ envParserPath,
98
+ envParserImportPattern,
99
+ loggerPath,
100
+ loggerImportPattern,
101
+ telescope,
102
+ studio,
103
+ hooks,
104
+ production,
105
+ };
106
+
107
+ // Initialize generators
108
+ const endpointGenerator = new EndpointGenerator();
109
+ const functionGenerator = new FunctionGenerator();
110
+ const cronGenerator = new CronGenerator();
111
+ const subscriberGenerator = new SubscriberGenerator();
112
+
113
+ // Load all constructs in parallel
114
+ const [allEndpoints, allFunctions, allCrons, allSubscribers] =
115
+ await Promise.all([
116
+ endpointGenerator.load(config.routes),
117
+ config.functions ? functionGenerator.load(config.functions) : [],
118
+ config.crons ? cronGenerator.load(config.crons) : [],
119
+ config.subscribers ? subscriberGenerator.load(config.subscribers) : [],
120
+ ]);
121
+
122
+ logger.log(`Found ${allEndpoints.length} endpoints`);
123
+ logger.log(`Found ${allFunctions.length} functions`);
124
+ logger.log(`Found ${allCrons.length} crons`);
125
+ logger.log(`Found ${allSubscribers.length} subscribers`);
126
+
127
+ if (
128
+ allEndpoints.length === 0 &&
129
+ allFunctions.length === 0 &&
130
+ allCrons.length === 0 &&
131
+ allSubscribers.length === 0
132
+ ) {
133
+ logger.log(
134
+ 'No endpoints, functions, crons, or subscribers found to process',
135
+ );
136
+ return {};
137
+ }
138
+
139
+ // Ensure .gkm directory exists
140
+ const rootOutputDir = join(process.cwd(), '.gkm');
141
+ await mkdir(rootOutputDir, { recursive: true });
142
+
143
+ // Build for each provider and generate per-provider manifests
144
+ let result: BuildResult = {};
145
+ for (const provider of resolved.providers) {
146
+ const providerResult = await buildForProvider(
147
+ provider,
148
+ buildContext,
149
+ rootOutputDir,
150
+ endpointGenerator,
151
+ functionGenerator,
152
+ cronGenerator,
153
+ subscriberGenerator,
154
+ allEndpoints,
155
+ allFunctions,
156
+ allCrons,
157
+ allSubscribers,
158
+ resolved.enableOpenApi,
159
+ options.skipBundle ?? false,
160
+ options.stage,
161
+ );
162
+ // Keep the master key from the server provider
163
+ if (providerResult.masterKey) {
164
+ result = providerResult;
165
+ }
166
+ }
167
+ return result;
126
168
  }
127
169
 
128
170
  async function buildForProvider(
129
- provider: LegacyProvider,
130
- context: BuildContext,
131
- rootOutputDir: string,
132
- endpointGenerator: EndpointGenerator,
133
- functionGenerator: FunctionGenerator,
134
- cronGenerator: CronGenerator,
135
- subscriberGenerator: SubscriberGenerator,
136
- endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],
137
- functions: GeneratedConstruct<Function<any, any, any, any>>[],
138
- crons: GeneratedConstruct<Cron<any, any, any, any>>[],
139
- subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],
140
- enableOpenApi: boolean,
141
- ): Promise<void> {
142
- const outputDir = join(process.cwd(), '.gkm', provider);
143
-
144
- // Ensure output directory exists
145
- await mkdir(outputDir, { recursive: true });
146
-
147
- logger.log(`\nGenerating handlers for provider: ${provider}`);
148
-
149
- // Build all constructs in parallel
150
- const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(
151
- [
152
- endpointGenerator.build(context, endpoints, outputDir, {
153
- provider,
154
- enableOpenApi,
155
- }),
156
- functionGenerator.build(context, functions, outputDir, { provider }),
157
- cronGenerator.build(context, crons, outputDir, { provider }),
158
- subscriberGenerator.build(context, subscribers, outputDir, { provider }),
159
- ],
160
- );
161
-
162
- logger.log(
163
- `Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,
164
- );
165
-
166
- // Generate provider-specific manifest
167
- if (provider === 'server') {
168
- // For server, collect actual route metadata from endpoint constructs
169
- const routeMetadata: RouteInfo[] = await Promise.all(
170
- endpoints.map(async ({ construct }) => ({
171
- path: construct._path,
172
- method: construct.method,
173
- handler: '', // Not needed for server manifest
174
- authorizer: construct.authorizer?.name ?? 'none',
175
- })),
176
- );
177
-
178
- const appInfo: ServerAppInfo = {
179
- handler: relative(process.cwd(), join(outputDir, 'app.ts')),
180
- endpoints: relative(process.cwd(), join(outputDir, 'endpoints.ts')),
181
- };
182
-
183
- await generateServerManifest(
184
- rootOutputDir,
185
- appInfo,
186
- routeMetadata,
187
- subscriberInfos,
188
- );
189
- } else {
190
- // For AWS providers, generate AWS manifest
191
- await generateAwsManifest(
192
- rootOutputDir,
193
- routes,
194
- functionInfos,
195
- cronInfos,
196
- subscriberInfos,
197
- );
198
- }
171
+ provider: LegacyProvider,
172
+ context: BuildContext,
173
+ rootOutputDir: string,
174
+ endpointGenerator: EndpointGenerator,
175
+ functionGenerator: FunctionGenerator,
176
+ cronGenerator: CronGenerator,
177
+ subscriberGenerator: SubscriberGenerator,
178
+ endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],
179
+ functions: GeneratedConstruct<Function<any, any, any, any>>[],
180
+ crons: GeneratedConstruct<Cron<any, any, any, any>>[],
181
+ subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],
182
+ enableOpenApi: boolean,
183
+ skipBundle: boolean,
184
+ stage?: string,
185
+ ): Promise<BuildResult> {
186
+ const outputDir = join(process.cwd(), '.gkm', provider);
187
+
188
+ // Ensure output directory exists
189
+ await mkdir(outputDir, { recursive: true });
190
+
191
+ logger.log(`\nGenerating handlers for provider: ${provider}`);
192
+
193
+ // Build all constructs in parallel
194
+ const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(
195
+ [
196
+ endpointGenerator.build(context, endpoints, outputDir, {
197
+ provider,
198
+ enableOpenApi,
199
+ }),
200
+ functionGenerator.build(context, functions, outputDir, { provider }),
201
+ cronGenerator.build(context, crons, outputDir, { provider }),
202
+ subscriberGenerator.build(context, subscribers, outputDir, { provider }),
203
+ ],
204
+ );
205
+
206
+ logger.log(
207
+ `Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,
208
+ );
209
+
210
+ // Generate provider-specific manifest
211
+ if (provider === 'server') {
212
+ // For server, collect actual route metadata from endpoint constructs
213
+ const routeMetadata: RouteInfo[] = await Promise.all(
214
+ endpoints.map(async ({ construct }) => ({
215
+ path: construct._path,
216
+ method: construct.method,
217
+ handler: '', // Not needed for server manifest
218
+ authorizer: construct.authorizer?.name ?? 'none',
219
+ })),
220
+ );
221
+
222
+ const appInfo: ServerAppInfo = {
223
+ handler: relative(process.cwd(), join(outputDir, 'app.ts')),
224
+ endpoints: relative(process.cwd(), join(outputDir, 'endpoints.ts')),
225
+ };
226
+
227
+ await generateServerManifest(
228
+ rootOutputDir,
229
+ appInfo,
230
+ routeMetadata,
231
+ subscriberInfos,
232
+ );
233
+
234
+ // Bundle for production if enabled
235
+ let masterKey: string | undefined;
236
+ if (context.production?.bundle && !skipBundle) {
237
+ logger.log(`\n📦 Bundling production server...`);
238
+ const { bundleServer } = await import('./bundler');
239
+ const bundleResult = await bundleServer({
240
+ entryPoint: join(outputDir, 'server.ts'),
241
+ outputDir: join(outputDir, 'dist'),
242
+ minify: context.production.minify,
243
+ sourcemap: false,
244
+ external: context.production.external,
245
+ stage,
246
+ });
247
+ masterKey = bundleResult.masterKey;
248
+ logger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
249
+
250
+ // Display master key if secrets were injected
251
+ if (masterKey) {
252
+ logger.log(`\n🔐 Secrets encrypted for deployment`);
253
+ logger.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
254
+ }
255
+ }
256
+
257
+ return { masterKey };
258
+ } else {
259
+ // For AWS providers, generate AWS manifest
260
+ await generateAwsManifest(
261
+ rootOutputDir,
262
+ routes,
263
+ functionInfos,
264
+ cronInfos,
265
+ subscriberInfos,
266
+ );
267
+ }
268
+
269
+ return {};
199
270
  }
@@ -1,10 +1,10 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
- import { join, relative } from 'path';
2
+ import { join, relative } from 'node:path';
3
3
  import type {
4
- CronInfo,
5
- FunctionInfo,
6
- RouteInfo,
7
- SubscriberInfo,
4
+ CronInfo,
5
+ FunctionInfo,
6
+ RouteInfo,
7
+ SubscriberInfo,
8
8
  } from '../types';
9
9
 
10
10
  const logger = console;
@@ -12,24 +12,24 @@ const logger = console;
12
12
  export type ManifestProvider = 'aws' | 'server';
13
13
 
14
14
  export interface ServerAppInfo {
15
- handler: string;
16
- endpoints: string;
15
+ handler: string;
16
+ endpoints: string;
17
17
  }
18
18
 
19
19
  export async function generateAwsManifest(
20
- outputDir: string,
21
- routes: RouteInfo[],
22
- functions: FunctionInfo[],
23
- crons: CronInfo[],
24
- subscribers: SubscriberInfo[],
20
+ outputDir: string,
21
+ routes: RouteInfo[],
22
+ functions: FunctionInfo[],
23
+ crons: CronInfo[],
24
+ subscribers: SubscriberInfo[],
25
25
  ): Promise<void> {
26
- const manifestDir = join(outputDir, 'manifest');
27
- await mkdir(manifestDir, { recursive: true });
26
+ const manifestDir = join(outputDir, 'manifest');
27
+ await mkdir(manifestDir, { recursive: true });
28
28
 
29
- // Filter out 'ALL' method routes (server-specific)
30
- const awsRoutes = routes.filter((r) => r.method !== 'ALL');
29
+ // Filter out 'ALL' method routes (server-specific)
30
+ const awsRoutes = routes.filter((r) => r.method !== 'ALL');
31
31
 
32
- const content = `export const manifest = {
32
+ const content = `export const manifest = {
33
33
  routes: ${JSON.stringify(awsRoutes, null, 2)},
34
34
  functions: ${JSON.stringify(functions, null, 2)},
35
35
  crons: ${JSON.stringify(crons, null, 2)},
@@ -48,40 +48,40 @@ export type HttpMethod = Route['method'];
48
48
  export type RoutePath = Route['path'];
49
49
  `;
50
50
 
51
- const manifestPath = join(manifestDir, 'aws.ts');
52
- await writeFile(manifestPath, content);
51
+ const manifestPath = join(manifestDir, 'aws.ts');
52
+ await writeFile(manifestPath, content);
53
53
 
54
- logger.log(
55
- `Generated AWS manifest with ${awsRoutes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,
56
- );
57
- logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
54
+ logger.log(
55
+ `Generated AWS manifest with ${awsRoutes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,
56
+ );
57
+ logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
58
58
  }
59
59
 
60
60
  export async function generateServerManifest(
61
- outputDir: string,
62
- appInfo: ServerAppInfo,
63
- routes: RouteInfo[],
64
- subscribers: SubscriberInfo[],
61
+ outputDir: string,
62
+ appInfo: ServerAppInfo,
63
+ routes: RouteInfo[],
64
+ subscribers: SubscriberInfo[],
65
65
  ): Promise<void> {
66
- const manifestDir = join(outputDir, 'manifest');
67
- await mkdir(manifestDir, { recursive: true });
68
-
69
- // For server, extract route metadata (path, method, authorizer)
70
- const serverRoutes = routes
71
- .filter((r) => r.method !== 'ALL')
72
- .map((r) => ({
73
- path: r.path,
74
- method: r.method,
75
- authorizer: r.authorizer,
76
- }));
77
-
78
- // Server subscribers only need name and events
79
- const serverSubscribers = subscribers.map((s) => ({
80
- name: s.name,
81
- subscribedEvents: s.subscribedEvents,
82
- }));
83
-
84
- const content = `export const manifest = {
66
+ const manifestDir = join(outputDir, 'manifest');
67
+ await mkdir(manifestDir, { recursive: true });
68
+
69
+ // For server, extract route metadata (path, method, authorizer)
70
+ const serverRoutes = routes
71
+ .filter((r) => r.method !== 'ALL')
72
+ .map((r) => ({
73
+ path: r.path,
74
+ method: r.method,
75
+ authorizer: r.authorizer,
76
+ }));
77
+
78
+ // Server subscribers only need name and events
79
+ const serverSubscribers = subscribers.map((s) => ({
80
+ name: s.name,
81
+ subscribedEvents: s.subscribedEvents,
82
+ }));
83
+
84
+ const content = `export const manifest = {
85
85
  app: ${JSON.stringify(appInfo, null, 2)},
86
86
  routes: ${JSON.stringify(serverRoutes, null, 2)},
87
87
  subscribers: ${JSON.stringify(serverSubscribers, null, 2)},
@@ -97,11 +97,11 @@ export type HttpMethod = Route['method'];
97
97
  export type RoutePath = Route['path'];
98
98
  `;
99
99
 
100
- const manifestPath = join(manifestDir, 'server.ts');
101
- await writeFile(manifestPath, content);
100
+ const manifestPath = join(manifestDir, 'server.ts');
101
+ await writeFile(manifestPath, content);
102
102
 
103
- logger.log(
104
- `Generated server manifest with ${serverRoutes.length} routes, ${serverSubscribers.length} subscribers`,
105
- );
106
- logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
103
+ logger.log(
104
+ `Generated server manifest with ${serverRoutes.length} routes, ${serverSubscribers.length} subscribers`,
105
+ );
106
+ logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
107
107
  }