@geekmidas/cli 0.0.26 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FUNCTION_CRON_SUPPORT.md +266 -0
- package/README.md +84 -17
- package/dist/CronGenerator-1PflEYe2.cjs +60 -0
- package/dist/CronGenerator-1PflEYe2.cjs.map +1 -0
- package/dist/CronGenerator-DXRfHQcV.mjs +54 -0
- package/dist/CronGenerator-DXRfHQcV.mjs.map +1 -0
- package/dist/EndpointGenerator-BbGrDiCP.cjs +264 -0
- package/dist/EndpointGenerator-BbGrDiCP.cjs.map +1 -0
- package/dist/EndpointGenerator-BmZ9BxbO.mjs +258 -0
- package/dist/EndpointGenerator-BmZ9BxbO.mjs.map +1 -0
- package/dist/FunctionGenerator-Clw64SwQ.cjs +59 -0
- package/dist/FunctionGenerator-Clw64SwQ.cjs.map +1 -0
- package/dist/FunctionGenerator-DOEB_yPh.mjs +53 -0
- package/dist/FunctionGenerator-DOEB_yPh.mjs.map +1 -0
- package/dist/Generator-CDoEXCDg.cjs +47 -0
- package/dist/Generator-CDoEXCDg.cjs.map +1 -0
- package/dist/Generator-UanJW0_V.mjs +41 -0
- package/dist/Generator-UanJW0_V.mjs.map +1 -0
- package/dist/SubscriberGenerator-BfMZCVNy.cjs +204 -0
- package/dist/SubscriberGenerator-BfMZCVNy.cjs.map +1 -0
- package/dist/SubscriberGenerator-D2u00NI3.mjs +198 -0
- package/dist/SubscriberGenerator-D2u00NI3.mjs.map +1 -0
- package/dist/build/index.cjs +12 -0
- package/dist/build/index.mjs +12 -0
- package/dist/build/manifests.cjs +3 -0
- package/dist/build/manifests.mjs +3 -0
- package/dist/build/providerResolver.cjs +5 -0
- package/dist/build/providerResolver.mjs +3 -0
- package/dist/build/types.cjs +0 -0
- package/dist/build/types.mjs +0 -0
- package/dist/build-BBhlEjf5.cjs +89 -0
- package/dist/build-BBhlEjf5.cjs.map +1 -0
- package/dist/build-kY-lG30Q.mjs +83 -0
- package/dist/build-kY-lG30Q.mjs.map +1 -0
- package/dist/config-D1EpSGk6.cjs +36 -0
- package/dist/config-D1EpSGk6.cjs.map +1 -0
- package/dist/config-U-mdW-7Y.mjs +30 -0
- package/dist/config-U-mdW-7Y.mjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.mjs +1 -1
- package/dist/generators/CronGenerator.cjs +4 -0
- package/dist/generators/CronGenerator.mjs +4 -0
- package/dist/generators/EndpointGenerator.cjs +4 -0
- package/dist/generators/EndpointGenerator.mjs +4 -0
- package/dist/generators/FunctionGenerator.cjs +4 -0
- package/dist/generators/FunctionGenerator.mjs +4 -0
- package/dist/generators/Generator.cjs +3 -0
- package/dist/generators/Generator.mjs +3 -0
- package/dist/generators/SubscriberGenerator.cjs +4 -0
- package/dist/generators/SubscriberGenerator.mjs +4 -0
- package/dist/generators/index.cjs +12 -0
- package/dist/generators/index.mjs +8 -0
- package/dist/generators-CEKtVh81.cjs +0 -0
- package/dist/generators-CsLujGXs.mjs +0 -0
- package/dist/index.cjs +71 -25
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +71 -25
- package/dist/index.mjs.map +1 -0
- package/dist/manifests-BrJXpHrf.mjs +21 -0
- package/dist/manifests-BrJXpHrf.mjs.map +1 -0
- package/dist/manifests-D0saShvH.cjs +27 -0
- package/dist/manifests-D0saShvH.cjs.map +1 -0
- package/dist/{openapi-CksVdkh2.mjs → openapi-BQx3_JbM.mjs} +8 -6
- package/dist/openapi-BQx3_JbM.mjs.map +1 -0
- package/dist/{openapi-D4QQJUPY.cjs → openapi-CMLr04cz.cjs} +9 -7
- package/dist/openapi-CMLr04cz.cjs.map +1 -0
- package/dist/{openapi-react-query-DpT3XHFC.mjs → openapi-react-query-DbrWwQzb.mjs} +5 -3
- package/dist/openapi-react-query-DbrWwQzb.mjs.map +1 -0
- package/dist/{openapi-react-query-C1JLYUOs.cjs → openapi-react-query-Dvjqx_Eo.cjs} +5 -3
- package/dist/openapi-react-query-Dvjqx_Eo.cjs.map +1 -0
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +4 -3
- package/dist/openapi.mjs +4 -3
- package/dist/providerResolver-B_TjNF0_.mjs +96 -0
- package/dist/providerResolver-B_TjNF0_.mjs.map +1 -0
- package/dist/providerResolver-DgvzNfP4.cjs +114 -0
- package/dist/providerResolver-DgvzNfP4.cjs.map +1 -0
- package/examples/cron-example.ts +45 -0
- package/examples/function-example.ts +40 -0
- package/examples/gkm.config.json +22 -0
- package/examples/gkm.minimal.config.json +7 -0
- package/examples/gkm.production.config.json +27 -0
- package/examples/logger.ts +1 -1
- package/package.json +38 -14
- package/src/__tests__/config.spec.ts +110 -0
- package/src/__tests__/openapi-react-query.spec.ts +506 -0
- package/src/__tests__/openapi.spec.ts +362 -0
- package/src/__tests__/test-helpers.ts +180 -0
- package/src/build/__tests__/index-new.spec.ts +577 -0
- package/src/build/index.ts +197 -0
- package/src/build/manifests.ts +35 -0
- package/src/build/providerResolver.ts +184 -0
- package/src/build/types.ts +37 -0
- package/src/config.ts +14 -6
- package/src/generators/CronGenerator.ts +98 -0
- package/src/generators/EndpointGenerator.ts +389 -0
- package/src/generators/FunctionGenerator.ts +97 -0
- package/src/generators/Generator.ts +95 -0
- package/src/generators/SubscriberGenerator.ts +271 -0
- package/src/generators/__tests__/CronGenerator.spec.ts +445 -0
- package/src/generators/__tests__/EndpointGenerator.spec.ts +394 -0
- package/src/generators/__tests__/FunctionGenerator.spec.ts +256 -0
- package/src/generators/__tests__/SubscriberGenerator.spec.ts +341 -0
- package/src/generators/index.ts +9 -0
- package/src/index.ts +57 -22
- package/src/openapi-react-query.ts +2 -1
- package/src/openapi.ts +5 -4
- package/src/types.ts +91 -2
- package/dist/build-BTggTCYL.cjs +0 -176
- package/dist/build-Ca4P6_lY.mjs +0 -170
- package/dist/build.cjs +0 -5
- package/dist/build.mjs +0 -5
- package/dist/config-BNqUMsvc.cjs +0 -24
- package/dist/config-BciAdY6_.mjs +0 -18
- package/dist/loadEndpoints-BBIavB9h.cjs +0 -37
- package/dist/loadEndpoints-DAZ53Og2.mjs +0 -31
- package/dist/loadEndpoints.cjs +0 -3
- package/dist/loadEndpoints.mjs +0 -3
- package/src/build.ts +0 -305
- package/src/loadEndpoints.ts +0 -48
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
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';
|
|
7
|
+
import { loadConfig } from '../config';
|
|
8
|
+
import {
|
|
9
|
+
CronGenerator,
|
|
10
|
+
EndpointGenerator,
|
|
11
|
+
FunctionGenerator,
|
|
12
|
+
type GeneratedConstruct,
|
|
13
|
+
SubscriberGenerator,
|
|
14
|
+
} from '../generators';
|
|
15
|
+
import type {
|
|
16
|
+
BuildOptions,
|
|
17
|
+
CronInfo,
|
|
18
|
+
FunctionInfo,
|
|
19
|
+
LegacyProvider,
|
|
20
|
+
RouteInfo,
|
|
21
|
+
SubscriberInfo,
|
|
22
|
+
} from '../types';
|
|
23
|
+
import { generateManifests } from './manifests';
|
|
24
|
+
import { resolveProviders } from './providerResolver';
|
|
25
|
+
import type { BuildContext } from './types';
|
|
26
|
+
|
|
27
|
+
const logger = console;
|
|
28
|
+
|
|
29
|
+
export async function buildCommand(options: BuildOptions): Promise<void> {
|
|
30
|
+
const config = await loadConfig();
|
|
31
|
+
|
|
32
|
+
// Resolve providers from new config format
|
|
33
|
+
const resolved = resolveProviders(config, options);
|
|
34
|
+
|
|
35
|
+
logger.log(`Building with providers: ${resolved.providers.join(', ')}`);
|
|
36
|
+
logger.log(`Loading routes from: ${config.routes}`);
|
|
37
|
+
if (config.functions) {
|
|
38
|
+
logger.log(`Loading functions from: ${config.functions}`);
|
|
39
|
+
}
|
|
40
|
+
if (config.crons) {
|
|
41
|
+
logger.log(`Loading crons from: ${config.crons}`);
|
|
42
|
+
}
|
|
43
|
+
if (config.subscribers) {
|
|
44
|
+
logger.log(`Loading subscribers from: ${config.subscribers}`);
|
|
45
|
+
}
|
|
46
|
+
logger.log(`Using envParser: ${config.envParser}`);
|
|
47
|
+
|
|
48
|
+
// Parse envParser configuration
|
|
49
|
+
const [envParserPath, envParserName] = config.envParser.split('#');
|
|
50
|
+
const envParserImportPattern = !envParserName
|
|
51
|
+
? 'envParser'
|
|
52
|
+
: envParserName === 'envParser'
|
|
53
|
+
? '{ envParser }'
|
|
54
|
+
: `{ ${envParserName} as envParser }`;
|
|
55
|
+
|
|
56
|
+
// Parse logger configuration
|
|
57
|
+
const [loggerPath, loggerName] = config.logger.split('#');
|
|
58
|
+
const loggerImportPattern = !loggerName
|
|
59
|
+
? 'logger'
|
|
60
|
+
: loggerName === 'logger'
|
|
61
|
+
? '{ logger }'
|
|
62
|
+
: `{ ${loggerName} as logger }`;
|
|
63
|
+
|
|
64
|
+
const buildContext: BuildContext = {
|
|
65
|
+
envParserPath,
|
|
66
|
+
envParserImportPattern,
|
|
67
|
+
loggerPath,
|
|
68
|
+
loggerImportPattern,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Initialize generators
|
|
72
|
+
const endpointGenerator = new EndpointGenerator();
|
|
73
|
+
const functionGenerator = new FunctionGenerator();
|
|
74
|
+
const cronGenerator = new CronGenerator();
|
|
75
|
+
const subscriberGenerator = new SubscriberGenerator();
|
|
76
|
+
|
|
77
|
+
// Load all constructs in parallel
|
|
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
|
+
]);
|
|
85
|
+
|
|
86
|
+
logger.log(`Found ${allEndpoints.length} endpoints`);
|
|
87
|
+
logger.log(`Found ${allFunctions.length} functions`);
|
|
88
|
+
logger.log(`Found ${allCrons.length} crons`);
|
|
89
|
+
logger.log(`Found ${allSubscribers.length} subscribers`);
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
allEndpoints.length === 0 &&
|
|
93
|
+
allFunctions.length === 0 &&
|
|
94
|
+
allCrons.length === 0 &&
|
|
95
|
+
allSubscribers.length === 0
|
|
96
|
+
) {
|
|
97
|
+
logger.log(
|
|
98
|
+
'No endpoints, functions, crons, or subscribers found to process',
|
|
99
|
+
);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
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(
|
|
109
|
+
resolved.providers.map((provider) =>
|
|
110
|
+
buildForProvider(
|
|
111
|
+
provider,
|
|
112
|
+
buildContext,
|
|
113
|
+
endpointGenerator,
|
|
114
|
+
functionGenerator,
|
|
115
|
+
cronGenerator,
|
|
116
|
+
subscriberGenerator,
|
|
117
|
+
allEndpoints,
|
|
118
|
+
allFunctions,
|
|
119
|
+
allCrons,
|
|
120
|
+
allSubscribers,
|
|
121
|
+
resolved.enableOpenApi,
|
|
122
|
+
),
|
|
123
|
+
),
|
|
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[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function buildForProvider(
|
|
154
|
+
provider: LegacyProvider,
|
|
155
|
+
context: BuildContext,
|
|
156
|
+
endpointGenerator: EndpointGenerator,
|
|
157
|
+
functionGenerator: FunctionGenerator,
|
|
158
|
+
cronGenerator: CronGenerator,
|
|
159
|
+
subscriberGenerator: SubscriberGenerator,
|
|
160
|
+
endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],
|
|
161
|
+
functions: GeneratedConstruct<Function<any, any, any, any>>[],
|
|
162
|
+
crons: GeneratedConstruct<Cron<any, any, any, any>>[],
|
|
163
|
+
subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],
|
|
164
|
+
enableOpenApi: boolean,
|
|
165
|
+
): Promise<BuildResult> {
|
|
166
|
+
const outputDir = join(process.cwd(), '.gkm', provider);
|
|
167
|
+
|
|
168
|
+
// Ensure output directory exists
|
|
169
|
+
await mkdir(outputDir, { recursive: true });
|
|
170
|
+
|
|
171
|
+
logger.log(`\nGenerating handlers for provider: ${provider}`);
|
|
172
|
+
|
|
173
|
+
// Build all constructs in parallel
|
|
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
|
+
],
|
|
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
|
+
};
|
|
197
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
|
+
import type {
|
|
4
|
+
BuildManifest,
|
|
5
|
+
CronInfo,
|
|
6
|
+
FunctionInfo,
|
|
7
|
+
RouteInfo,
|
|
8
|
+
SubscriberInfo,
|
|
9
|
+
} from '../types';
|
|
10
|
+
|
|
11
|
+
const logger = console;
|
|
12
|
+
|
|
13
|
+
export async function generateManifests(
|
|
14
|
+
outputDir: string,
|
|
15
|
+
routes: RouteInfo[],
|
|
16
|
+
functions: FunctionInfo[],
|
|
17
|
+
crons: CronInfo[],
|
|
18
|
+
subscribers: SubscriberInfo[],
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
// Generate unified manifest for all providers
|
|
21
|
+
const manifest: BuildManifest = {
|
|
22
|
+
routes,
|
|
23
|
+
functions,
|
|
24
|
+
crons,
|
|
25
|
+
subscribers,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const manifestPath = join(outputDir, 'manifest.json');
|
|
29
|
+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
30
|
+
|
|
31
|
+
logger.log(
|
|
32
|
+
`\nGenerated unified manifest with ${routes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,
|
|
33
|
+
);
|
|
34
|
+
logger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
|
|
35
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AWSApiGatewayConfig,
|
|
3
|
+
AWSLambdaConfig,
|
|
4
|
+
BuildOptions,
|
|
5
|
+
GkmConfig,
|
|
6
|
+
LegacyProvider,
|
|
7
|
+
MainProvider,
|
|
8
|
+
ProvidersConfig,
|
|
9
|
+
ServerConfig,
|
|
10
|
+
} from '../types';
|
|
11
|
+
|
|
12
|
+
export interface ResolvedProviders {
|
|
13
|
+
providers: LegacyProvider[];
|
|
14
|
+
enableOpenApi: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves provider configuration from the new simplified system
|
|
19
|
+
* to the internal legacy format for backward compatibility
|
|
20
|
+
*/
|
|
21
|
+
export function resolveProviders(
|
|
22
|
+
config: GkmConfig,
|
|
23
|
+
options: BuildOptions,
|
|
24
|
+
): ResolvedProviders {
|
|
25
|
+
const providers: LegacyProvider[] = [];
|
|
26
|
+
let enableOpenApi = options.enableOpenApi || false;
|
|
27
|
+
|
|
28
|
+
// Handle legacy providers option (deprecated)
|
|
29
|
+
if (options.providers) {
|
|
30
|
+
return {
|
|
31
|
+
providers: options.providers,
|
|
32
|
+
enableOpenApi,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Handle new provider option
|
|
37
|
+
if (options.provider) {
|
|
38
|
+
const resolvedProviders = resolveMainProvider(
|
|
39
|
+
options.provider,
|
|
40
|
+
config.providers,
|
|
41
|
+
);
|
|
42
|
+
providers.push(...resolvedProviders.providers);
|
|
43
|
+
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
44
|
+
}
|
|
45
|
+
// Default: build all configured providers
|
|
46
|
+
else if (config.providers) {
|
|
47
|
+
const resolvedProviders = resolveAllConfiguredProviders(config.providers);
|
|
48
|
+
providers.push(...resolvedProviders.providers);
|
|
49
|
+
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
50
|
+
}
|
|
51
|
+
// Fallback: use default AWS configuration
|
|
52
|
+
else {
|
|
53
|
+
providers.push('aws-apigatewayv2', 'aws-lambda');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
providers: [...new Set(providers)], // Remove duplicates
|
|
58
|
+
enableOpenApi,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveMainProvider(
|
|
63
|
+
mainProvider: MainProvider,
|
|
64
|
+
providersConfig?: ProvidersConfig,
|
|
65
|
+
): ResolvedProviders {
|
|
66
|
+
const providers: LegacyProvider[] = [];
|
|
67
|
+
let enableOpenApi = false;
|
|
68
|
+
|
|
69
|
+
if (mainProvider === 'aws') {
|
|
70
|
+
const awsConfig = providersConfig?.aws;
|
|
71
|
+
|
|
72
|
+
// Resolve API Gateway providers
|
|
73
|
+
if (awsConfig?.apiGateway) {
|
|
74
|
+
if (isEnabled(awsConfig.apiGateway.v1)) {
|
|
75
|
+
providers.push('aws-apigatewayv1');
|
|
76
|
+
}
|
|
77
|
+
if (isEnabled(awsConfig.apiGateway.v2)) {
|
|
78
|
+
providers.push('aws-apigatewayv2');
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
// Default: enable v2 if no specific config
|
|
82
|
+
providers.push('aws-apigatewayv2');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Resolve Lambda providers
|
|
86
|
+
if (awsConfig?.lambda) {
|
|
87
|
+
if (
|
|
88
|
+
isEnabled(awsConfig.lambda.functions) ||
|
|
89
|
+
isEnabled(awsConfig.lambda.crons)
|
|
90
|
+
) {
|
|
91
|
+
providers.push('aws-lambda');
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// Default: enable lambda if no specific config
|
|
95
|
+
providers.push('aws-lambda');
|
|
96
|
+
}
|
|
97
|
+
} else if (mainProvider === 'server') {
|
|
98
|
+
providers.push('server');
|
|
99
|
+
const serverConfig = providersConfig?.server;
|
|
100
|
+
|
|
101
|
+
if (typeof serverConfig === 'object' && serverConfig?.enableOpenApi) {
|
|
102
|
+
enableOpenApi = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { providers, enableOpenApi };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function resolveAllConfiguredProviders(
|
|
110
|
+
providersConfig: ProvidersConfig,
|
|
111
|
+
): ResolvedProviders {
|
|
112
|
+
const providers: LegacyProvider[] = [];
|
|
113
|
+
let enableOpenApi = false;
|
|
114
|
+
|
|
115
|
+
// AWS providers
|
|
116
|
+
if (providersConfig.aws) {
|
|
117
|
+
const awsProviders = resolveMainProvider('aws', providersConfig);
|
|
118
|
+
providers.push(...awsProviders.providers);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Server provider
|
|
122
|
+
if (providersConfig.server && isEnabled(providersConfig.server)) {
|
|
123
|
+
providers.push('server');
|
|
124
|
+
if (
|
|
125
|
+
typeof providersConfig.server === 'object' &&
|
|
126
|
+
providersConfig.server.enableOpenApi
|
|
127
|
+
) {
|
|
128
|
+
enableOpenApi = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { providers, enableOpenApi };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function isEnabled(
|
|
136
|
+
config:
|
|
137
|
+
| boolean
|
|
138
|
+
| AWSApiGatewayConfig
|
|
139
|
+
| AWSLambdaConfig
|
|
140
|
+
| ServerConfig
|
|
141
|
+
| undefined,
|
|
142
|
+
): boolean {
|
|
143
|
+
if (config === undefined) return false;
|
|
144
|
+
if (typeof config === 'boolean') return config;
|
|
145
|
+
return config.enabled !== false; // Default to true if enabled is not explicitly false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Gets configuration for a specific AWS service
|
|
150
|
+
*/
|
|
151
|
+
export function getAWSServiceConfig<
|
|
152
|
+
T extends AWSApiGatewayConfig | AWSLambdaConfig,
|
|
153
|
+
>(
|
|
154
|
+
config: GkmConfig,
|
|
155
|
+
service: 'apiGateway' | 'lambda',
|
|
156
|
+
subService?: 'v1' | 'v2' | 'functions' | 'crons',
|
|
157
|
+
): T | undefined {
|
|
158
|
+
const awsConfig = config.providers?.aws;
|
|
159
|
+
if (!awsConfig) return undefined;
|
|
160
|
+
|
|
161
|
+
if (service === 'apiGateway' && awsConfig.apiGateway) {
|
|
162
|
+
const apiConfig = subService
|
|
163
|
+
? awsConfig.apiGateway[subService as 'v1' | 'v2']
|
|
164
|
+
: undefined;
|
|
165
|
+
return typeof apiConfig === 'object' ? (apiConfig as T) : undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (service === 'lambda' && awsConfig.lambda) {
|
|
169
|
+
const lambdaConfig = subService
|
|
170
|
+
? awsConfig.lambda[subService as 'functions' | 'crons']
|
|
171
|
+
: undefined;
|
|
172
|
+
return typeof lambdaConfig === 'object' ? (lambdaConfig as T) : undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Gets server configuration
|
|
180
|
+
*/
|
|
181
|
+
export function getServerConfig(config: GkmConfig): ServerConfig | undefined {
|
|
182
|
+
const serverConfig = config.providers?.server;
|
|
183
|
+
return typeof serverConfig === 'object' ? serverConfig : undefined;
|
|
184
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Cron, Function } from '@geekmidas/constructs';
|
|
2
|
+
import type { Endpoint } from '@geekmidas/constructs';
|
|
3
|
+
|
|
4
|
+
import type { CronInfo, FunctionInfo, RouteInfo } from '../types';
|
|
5
|
+
|
|
6
|
+
export interface ProcessedEndpoint {
|
|
7
|
+
file: string;
|
|
8
|
+
exportName: string;
|
|
9
|
+
endpoint: Endpoint<any, any, any, any, any, any>;
|
|
10
|
+
routeInfo: RouteInfo;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ProcessedFunction {
|
|
14
|
+
file: string;
|
|
15
|
+
exportName: string;
|
|
16
|
+
fn: Function<any, any, any, any, any>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ProcessedCron {
|
|
20
|
+
file: string;
|
|
21
|
+
exportName: string;
|
|
22
|
+
cron: Cron<any, any, any, any>;
|
|
23
|
+
schedule?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface BuildContext {
|
|
27
|
+
envParserPath: string;
|
|
28
|
+
envParserImportPattern: string;
|
|
29
|
+
loggerPath: string;
|
|
30
|
+
loggerImportPattern: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ProviderBuildResult {
|
|
34
|
+
routes: RouteInfo[];
|
|
35
|
+
functions: FunctionInfo[];
|
|
36
|
+
crons: CronInfo[];
|
|
37
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import { readFile } from 'fs/promises';
|
|
4
3
|
import type { GkmConfig } from './types.ts';
|
|
5
4
|
|
|
6
5
|
export async function loadConfig(): Promise<GkmConfig> {
|
|
7
|
-
const
|
|
6
|
+
const files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];
|
|
7
|
+
let configPath = '';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
for (const file of files) {
|
|
10
|
+
const path = join(process.cwd(), file);
|
|
11
|
+
if (existsSync(path)) {
|
|
12
|
+
configPath = path;
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!configPath) {
|
|
10
18
|
throw new Error(
|
|
11
|
-
'
|
|
19
|
+
'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',
|
|
12
20
|
);
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
try {
|
|
16
|
-
const config = await
|
|
17
|
-
return
|
|
24
|
+
const config = await import(configPath);
|
|
25
|
+
return config.default;
|
|
18
26
|
} catch (error) {
|
|
19
27
|
throw new Error(
|
|
20
28
|
`Failed to load gkm.config.json: ${(error as Error).message}`,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join, relative } from 'node:path';
|
|
3
|
+
import { Cron } from '@geekmidas/constructs/crons';
|
|
4
|
+
import type { BuildContext } from '../build/types';
|
|
5
|
+
import type { CronInfo } from '../types';
|
|
6
|
+
import {
|
|
7
|
+
ConstructGenerator,
|
|
8
|
+
type GeneratedConstruct,
|
|
9
|
+
type GeneratorOptions,
|
|
10
|
+
} from './Generator';
|
|
11
|
+
|
|
12
|
+
export class CronGenerator extends ConstructGenerator<
|
|
13
|
+
Cron<any, any, any, any>,
|
|
14
|
+
CronInfo[]
|
|
15
|
+
> {
|
|
16
|
+
async build(
|
|
17
|
+
context: BuildContext,
|
|
18
|
+
constructs: GeneratedConstruct<Cron<any, any, any, any>>[],
|
|
19
|
+
outputDir: string,
|
|
20
|
+
options?: GeneratorOptions,
|
|
21
|
+
): Promise<CronInfo[]> {
|
|
22
|
+
const provider = options?.provider || 'aws-lambda';
|
|
23
|
+
const logger = console;
|
|
24
|
+
const cronInfos: CronInfo[] = [];
|
|
25
|
+
|
|
26
|
+
if (constructs.length === 0 || provider !== 'aws-lambda') {
|
|
27
|
+
return cronInfos;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Create crons subdirectory
|
|
31
|
+
const cronsDir = join(outputDir, 'crons');
|
|
32
|
+
await mkdir(cronsDir, { recursive: true });
|
|
33
|
+
|
|
34
|
+
// Generate cron handlers
|
|
35
|
+
for (const { key, construct, path } of constructs) {
|
|
36
|
+
const handlerFile = await this.generateCronHandler(
|
|
37
|
+
cronsDir,
|
|
38
|
+
path.relative,
|
|
39
|
+
key,
|
|
40
|
+
context,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
cronInfos.push({
|
|
44
|
+
name: key,
|
|
45
|
+
handler: relative(process.cwd(), handlerFile).replace(
|
|
46
|
+
/\.ts$/,
|
|
47
|
+
'.handler',
|
|
48
|
+
),
|
|
49
|
+
schedule: construct.schedule || 'rate(1 hour)',
|
|
50
|
+
timeout: construct.timeout,
|
|
51
|
+
environment: await construct.getEnvironment(),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
logger.log(`Generated cron handler: ${key}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return cronInfos;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
isConstruct(value: any): value is Cron<any, any, any, any> {
|
|
61
|
+
return Cron.isCron(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private async generateCronHandler(
|
|
65
|
+
outputDir: string,
|
|
66
|
+
sourceFile: string,
|
|
67
|
+
exportName: string,
|
|
68
|
+
context: BuildContext,
|
|
69
|
+
): Promise<string> {
|
|
70
|
+
const handlerFileName = `${exportName}.ts`;
|
|
71
|
+
const handlerPath = join(outputDir, handlerFileName);
|
|
72
|
+
|
|
73
|
+
const relativePath = relative(dirname(handlerPath), sourceFile);
|
|
74
|
+
const importPath = relativePath.replace(/\.ts$/, '.js');
|
|
75
|
+
|
|
76
|
+
const relativeEnvParserPath = relative(
|
|
77
|
+
dirname(handlerPath),
|
|
78
|
+
context.envParserPath,
|
|
79
|
+
);
|
|
80
|
+
const relativeLoggerPath = relative(
|
|
81
|
+
dirname(handlerPath),
|
|
82
|
+
context.loggerPath,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const content = `import { AWSScheduledFunction } from '@geekmidas/constructs/crons';
|
|
86
|
+
import { ${exportName} } from '${importPath}';
|
|
87
|
+
import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
|
|
88
|
+
import ${context.loggerImportPattern} from '${relativeLoggerPath}';
|
|
89
|
+
|
|
90
|
+
const adapter = new AWSScheduledFunction(envParser, ${exportName});
|
|
91
|
+
|
|
92
|
+
export const handler = adapter.handler;
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
await writeFile(handlerPath, content);
|
|
96
|
+
return handlerPath;
|
|
97
|
+
}
|
|
98
|
+
}
|