@geekmidas/cli 0.10.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 (145) 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-C9aXOHBe.cjs → config-AmInkU7k.cjs} +8 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-BrkUalUh.mjs → config-DYULeEv8.mjs} +3 -3
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +1 -1
  12. package/dist/config.d.mts +1 -1
  13. package/dist/config.mjs +1 -1
  14. package/dist/encryption-C8H-38Yy.mjs +42 -0
  15. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  16. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  17. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  18. package/dist/index.cjs +2116 -179
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +2134 -192
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-CZLI4QTr.mjs → openapi-BfFlOBCG.mjs} +801 -38
  23. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  24. package/dist/{openapi-BeHLKcwP.cjs → openapi-Bt_1FDpT.cjs} +794 -31
  25. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  26. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  27. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  28. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  29. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  30. package/dist/openapi-react-query.cjs +1 -1
  31. package/dist/openapi-react-query.d.cts.map +1 -1
  32. package/dist/openapi-react-query.d.mts.map +1 -1
  33. package/dist/openapi-react-query.mjs +1 -1
  34. package/dist/openapi.cjs +2 -2
  35. package/dist/openapi.d.cts +1 -1
  36. package/dist/openapi.d.cts.map +1 -1
  37. package/dist/openapi.d.mts +1 -1
  38. package/dist/openapi.d.mts.map +1 -1
  39. package/dist/openapi.mjs +2 -2
  40. package/dist/storage-BUYQJgz7.cjs +4 -0
  41. package/dist/storage-BXoJvmv2.cjs +149 -0
  42. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  43. package/dist/storage-C9PU_30f.mjs +101 -0
  44. package/dist/storage-C9PU_30f.mjs.map +1 -0
  45. package/dist/storage-DLJAYxzJ.mjs +3 -0
  46. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  47. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  48. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  49. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  50. package/examples/cron-example.ts +27 -27
  51. package/examples/env.ts +27 -27
  52. package/examples/function-example.ts +31 -31
  53. package/examples/gkm.config.json +20 -20
  54. package/examples/gkm.config.ts +8 -8
  55. package/examples/gkm.minimal.config.json +5 -5
  56. package/examples/gkm.production.config.json +25 -25
  57. package/examples/logger.ts +2 -2
  58. package/package.json +6 -6
  59. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  60. package/src/__tests__/config.spec.ts +55 -55
  61. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  62. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  63. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  64. package/src/__tests__/openapi.spec.ts +428 -428
  65. package/src/__tests__/test-helpers.ts +76 -76
  66. package/src/auth/__tests__/credentials.spec.ts +204 -0
  67. package/src/auth/__tests__/index.spec.ts +168 -0
  68. package/src/auth/credentials.ts +187 -0
  69. package/src/auth/index.ts +226 -0
  70. package/src/build/__tests__/index-new.spec.ts +474 -474
  71. package/src/build/__tests__/manifests.spec.ts +333 -333
  72. package/src/build/bundler.ts +141 -0
  73. package/src/build/endpoint-analyzer.ts +236 -0
  74. package/src/build/handler-templates.ts +1253 -0
  75. package/src/build/index.ts +250 -179
  76. package/src/build/manifests.ts +52 -52
  77. package/src/build/providerResolver.ts +145 -145
  78. package/src/build/types.ts +64 -43
  79. package/src/config.ts +39 -39
  80. package/src/deploy/__tests__/docker.spec.ts +111 -0
  81. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  82. package/src/deploy/__tests__/init.spec.ts +662 -0
  83. package/src/deploy/docker.ts +128 -0
  84. package/src/deploy/dokploy.ts +204 -0
  85. package/src/deploy/index.ts +136 -0
  86. package/src/deploy/init.ts +484 -0
  87. package/src/deploy/types.ts +48 -0
  88. package/src/dev/__tests__/index.spec.ts +266 -266
  89. package/src/dev/index.ts +647 -601
  90. package/src/docker/__tests__/compose.spec.ts +531 -0
  91. package/src/docker/__tests__/templates.spec.ts +280 -0
  92. package/src/docker/compose.ts +273 -0
  93. package/src/docker/index.ts +230 -0
  94. package/src/docker/templates.ts +446 -0
  95. package/src/generators/CronGenerator.ts +72 -72
  96. package/src/generators/EndpointGenerator.ts +699 -398
  97. package/src/generators/FunctionGenerator.ts +84 -84
  98. package/src/generators/Generator.ts +72 -72
  99. package/src/generators/OpenApiTsGenerator.ts +577 -577
  100. package/src/generators/SubscriberGenerator.ts +124 -124
  101. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  102. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  103. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  104. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  105. package/src/generators/index.ts +4 -4
  106. package/src/index.ts +623 -201
  107. package/src/init/__tests__/generators.spec.ts +334 -334
  108. package/src/init/__tests__/init.spec.ts +332 -332
  109. package/src/init/__tests__/utils.spec.ts +89 -89
  110. package/src/init/generators/config.ts +175 -175
  111. package/src/init/generators/docker.ts +41 -41
  112. package/src/init/generators/env.ts +72 -72
  113. package/src/init/generators/index.ts +1 -1
  114. package/src/init/generators/models.ts +64 -64
  115. package/src/init/generators/monorepo.ts +161 -161
  116. package/src/init/generators/package.ts +71 -71
  117. package/src/init/generators/source.ts +6 -6
  118. package/src/init/index.ts +203 -208
  119. package/src/init/templates/api.ts +115 -115
  120. package/src/init/templates/index.ts +75 -75
  121. package/src/init/templates/minimal.ts +98 -98
  122. package/src/init/templates/serverless.ts +89 -89
  123. package/src/init/templates/worker.ts +98 -98
  124. package/src/init/utils.ts +54 -56
  125. package/src/openapi-react-query.ts +194 -194
  126. package/src/openapi.ts +63 -63
  127. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  128. package/src/secrets/__tests__/generator.spec.ts +319 -0
  129. package/src/secrets/__tests__/index.spec.ts +91 -0
  130. package/src/secrets/__tests__/storage.spec.ts +403 -0
  131. package/src/secrets/encryption.ts +91 -0
  132. package/src/secrets/generator.ts +164 -0
  133. package/src/secrets/index.ts +383 -0
  134. package/src/secrets/storage.ts +134 -0
  135. package/src/secrets/types.ts +53 -0
  136. package/src/types.ts +295 -176
  137. package/tsdown.config.ts +11 -8
  138. package/dist/config-BrkUalUh.mjs.map +0 -1
  139. package/dist/config-C9aXOHBe.cjs.map +0 -1
  140. package/dist/openapi-BeHLKcwP.cjs.map +0 -1
  141. package/dist/openapi-CZLI4QTr.mjs.map +0 -1
  142. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  143. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
  144. package/dist/types-DXgiA1sF.d.mts.map +0 -1
  145. package/dist/types-b-vwGpqc.d.cts.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
  }