@geekmidas/cli 0.0.26 → 0.1.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 +21 -4
- package/dist/CronGenerator-ClbRcmz_.mjs +53 -0
- package/dist/CronGenerator-ClbRcmz_.mjs.map +1 -0
- package/dist/CronGenerator-Ctl4USy4.cjs +59 -0
- package/dist/CronGenerator-Ctl4USy4.cjs.map +1 -0
- package/dist/EndpointGenerator-Dj7AumHi.cjs +164 -0
- package/dist/EndpointGenerator-Dj7AumHi.cjs.map +1 -0
- package/dist/EndpointGenerator-uBA1ixUw.mjs +158 -0
- package/dist/EndpointGenerator-uBA1ixUw.mjs.map +1 -0
- package/dist/FunctionGenerator-DN681IUn.cjs +58 -0
- package/dist/FunctionGenerator-DN681IUn.cjs.map +1 -0
- package/dist/FunctionGenerator-crAa-JC7.mjs +52 -0
- package/dist/FunctionGenerator-crAa-JC7.mjs.map +1 -0
- package/dist/Generator-C3tYSTQY.cjs +47 -0
- package/dist/Generator-C3tYSTQY.cjs.map +1 -0
- package/dist/Generator-CDt4pB3W.mjs +41 -0
- package/dist/Generator-CDt4pB3W.mjs.map +1 -0
- package/dist/__tests__/config.spec.cjs +98 -0
- package/dist/__tests__/config.spec.cjs.map +1 -0
- package/dist/__tests__/config.spec.mjs +97 -0
- package/dist/__tests__/config.spec.mjs.map +1 -0
- package/dist/__tests__/test-helpers.cjs +14 -0
- package/dist/__tests__/test-helpers.mjs +4 -0
- package/dist/build/__tests__/index-new.spec.cjs +286 -0
- package/dist/build/__tests__/index-new.spec.cjs.map +1 -0
- package/dist/build/__tests__/index-new.spec.mjs +285 -0
- package/dist/build/__tests__/index-new.spec.mjs.map +1 -0
- package/dist/build/index.cjs +11 -0
- package/dist/build/index.mjs +11 -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-BZdwxCLW.mjs +64 -0
- package/dist/build-BZdwxCLW.mjs.map +1 -0
- package/dist/build-BfQFnU5-.cjs +70 -0
- package/dist/build-BfQFnU5-.cjs.map +1 -0
- package/dist/{chunk-CUT6urMc.cjs → chunk-CsX-DzYB.cjs} +12 -0
- package/dist/config-CXxYmz_o.mjs +30 -0
- package/dist/config-CXxYmz_o.mjs.map +1 -0
- package/dist/config-RcNESK0T.cjs +36 -0
- package/dist/config-RcNESK0T.cjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.mjs +1 -1
- package/dist/esm-9eeZntth.mjs +3777 -0
- package/dist/esm-9eeZntth.mjs.map +1 -0
- package/dist/esm-Crmo4h9t.cjs +4392 -0
- package/dist/esm-Crmo4h9t.cjs.map +1 -0
- package/dist/esm-CsJbr7gi.mjs +3 -0
- package/dist/esm-w09tAC4l.cjs +8 -0
- 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/__tests__/CronGenerator.spec.cjs +216 -0
- package/dist/generators/__tests__/CronGenerator.spec.cjs.map +1 -0
- package/dist/generators/__tests__/CronGenerator.spec.mjs +215 -0
- package/dist/generators/__tests__/CronGenerator.spec.mjs.map +1 -0
- package/dist/generators/__tests__/EndpointGenerator.spec.cjs +182 -0
- package/dist/generators/__tests__/EndpointGenerator.spec.cjs.map +1 -0
- package/dist/generators/__tests__/EndpointGenerator.spec.mjs +181 -0
- package/dist/generators/__tests__/EndpointGenerator.spec.mjs.map +1 -0
- package/dist/generators/__tests__/FunctionGenerator.spec.cjs +152 -0
- package/dist/generators/__tests__/FunctionGenerator.spec.cjs.map +1 -0
- package/dist/generators/__tests__/FunctionGenerator.spec.mjs +151 -0
- package/dist/generators/__tests__/FunctionGenerator.spec.mjs.map +1 -0
- package/dist/generators/index.cjs +10 -0
- package/dist/generators/index.mjs +7 -0
- package/dist/generators-CsLujGXs.mjs +0 -0
- package/dist/generators-_pY7sHy1.cjs +0 -0
- package/dist/index.cjs +68 -26
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +67 -25
- package/dist/index.mjs.map +1 -0
- package/dist/manifests-BTtfDMX8.cjs +26 -0
- package/dist/manifests-BTtfDMX8.cjs.map +1 -0
- package/dist/manifests-HX4z4kkz.mjs +20 -0
- package/dist/manifests-HX4z4kkz.mjs.map +1 -0
- package/dist/{openapi-CksVdkh2.mjs → openapi-BivnatiC.mjs} +8 -6
- package/dist/openapi-BivnatiC.mjs.map +1 -0
- package/dist/{openapi-D4QQJUPY.cjs → openapi-DW-qF3oW.cjs} +9 -7
- package/dist/openapi-DW-qF3oW.cjs.map +1 -0
- package/dist/{openapi-react-query-C1JLYUOs.cjs → openapi-react-query-J0BzBHhN.cjs} +4 -3
- package/dist/openapi-react-query-J0BzBHhN.cjs.map +1 -0
- package/dist/{openapi-react-query-DpT3XHFC.mjs → openapi-react-query-lgS7AVEz.mjs} +3 -2
- package/dist/openapi-react-query-lgS7AVEz.mjs.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-Cs-0YCaP.cjs +114 -0
- package/dist/providerResolver-Cs-0YCaP.cjs.map +1 -0
- package/dist/test-helpers-ARd8GDgx.cjs +199 -0
- package/dist/test-helpers-ARd8GDgx.cjs.map +1 -0
- package/dist/test-helpers-DdVBk23F.mjs +133 -0
- package/dist/test-helpers-DdVBk23F.mjs.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/package.json +35 -14
- package/src/__tests__/config.spec.ts +110 -0
- package/src/__tests__/test-helpers.ts +178 -0
- package/src/build/__tests__/index-new.spec.ts +578 -0
- package/src/build/index.ts +136 -0
- package/src/build/manifests.ts +32 -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 +97 -0
- package/src/generators/EndpointGenerator.ts +290 -0
- package/src/generators/FunctionGenerator.ts +96 -0
- package/src/generators/Generator.ts +95 -0
- package/src/generators/__tests__/CronGenerator.spec.ts +445 -0
- package/src/generators/__tests__/EndpointGenerator.spec.ts +372 -0
- package/src/generators/__tests__/FunctionGenerator.spec.ts +257 -0
- package/src/generators/index.ts +8 -0
- package/src/index.ts +57 -22
- package/src/openapi.ts +4 -3
- package/src/types.ts +73 -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,110 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
import { loadConfig } from '../config';
|
|
5
|
+
import { cleanupDir, createTempDir } from './test-helpers';
|
|
6
|
+
|
|
7
|
+
describe('loadConfig', () => {
|
|
8
|
+
let tempDir: string;
|
|
9
|
+
let originalCwd: string;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
tempDir = await createTempDir();
|
|
13
|
+
originalCwd = process.cwd();
|
|
14
|
+
process.chdir(tempDir);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
process.chdir(originalCwd);
|
|
19
|
+
await cleanupDir(tempDir);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should load configuration from gkm.config.ts', async () => {
|
|
23
|
+
const configContent = `
|
|
24
|
+
export default {
|
|
25
|
+
routes: './src/endpoints/**/*.ts',
|
|
26
|
+
functions: './src/functions/**/*.ts',
|
|
27
|
+
crons: './src/crons/**/*.ts',
|
|
28
|
+
envParser: './src/config/env',
|
|
29
|
+
logger: './src/config/logger',
|
|
30
|
+
};
|
|
31
|
+
`;
|
|
32
|
+
await writeFile(join(tempDir, 'gkm.config.ts'), configContent);
|
|
33
|
+
|
|
34
|
+
const config = await loadConfig();
|
|
35
|
+
|
|
36
|
+
expect(config).toEqual({
|
|
37
|
+
routes: './src/endpoints/**/*.ts',
|
|
38
|
+
functions: './src/functions/**/*.ts',
|
|
39
|
+
crons: './src/crons/**/*.ts',
|
|
40
|
+
envParser: './src/config/env',
|
|
41
|
+
logger: './src/config/logger',
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should load configuration from gkm.config.js', async () => {
|
|
46
|
+
const configContent = `
|
|
47
|
+
module.exports = {
|
|
48
|
+
routes: './api/**/*.js',
|
|
49
|
+
envParser: './config/environment',
|
|
50
|
+
logger: './config/logging',
|
|
51
|
+
};
|
|
52
|
+
`;
|
|
53
|
+
await writeFile(join(tempDir, 'gkm.config.js'), configContent);
|
|
54
|
+
|
|
55
|
+
const config = await loadConfig();
|
|
56
|
+
|
|
57
|
+
expect(config.routes).toBe('./api/**/*.js');
|
|
58
|
+
expect(config.envParser).toBe('./config/environment');
|
|
59
|
+
expect(config.logger).toBe('./config/logging');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle configuration with only envParser override', async () => {
|
|
63
|
+
const configContent = `
|
|
64
|
+
export default {
|
|
65
|
+
envParser: './my-env#myEnvParser',
|
|
66
|
+
logger: './my-logger#myLogger',
|
|
67
|
+
};
|
|
68
|
+
`;
|
|
69
|
+
await writeFile(join(tempDir, 'gkm.config.ts'), configContent);
|
|
70
|
+
|
|
71
|
+
const config = await loadConfig();
|
|
72
|
+
|
|
73
|
+
expect(config.envParser).toBe('./my-env#myEnvParser');
|
|
74
|
+
expect(config.logger).toBe('./my-logger#myLogger');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should handle malformed config file gracefully', async () => {
|
|
78
|
+
const invalidConfigContent = `
|
|
79
|
+
export default {
|
|
80
|
+
routes: './endpoints/**/*.ts'
|
|
81
|
+
// Missing comma - syntax error
|
|
82
|
+
functions: './functions/**/*.ts'
|
|
83
|
+
};
|
|
84
|
+
`;
|
|
85
|
+
await writeFile(join(tempDir, 'gkm.config.ts'), invalidConfigContent);
|
|
86
|
+
|
|
87
|
+
// Should fall back to defaults when config file has syntax errors
|
|
88
|
+
await expect(loadConfig()).rejects.toThrow();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should prefer .ts config over .js config', async () => {
|
|
92
|
+
const jsConfigContent = `
|
|
93
|
+
module.exports = {
|
|
94
|
+
routes: './js-routes/**/*.js',
|
|
95
|
+
};
|
|
96
|
+
`;
|
|
97
|
+
const tsConfigContent = `
|
|
98
|
+
export default {
|
|
99
|
+
routes: './ts-routes/**/*.ts',
|
|
100
|
+
};
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
await writeFile(join(tempDir, 'gkm.config.js'), jsConfigContent);
|
|
104
|
+
await writeFile(join(tempDir, 'gkm.config.ts'), tsConfigContent);
|
|
105
|
+
|
|
106
|
+
const config = await loadConfig();
|
|
107
|
+
|
|
108
|
+
expect(config.routes).toBe('./ts-routes/**/*.ts');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
CronBuilder,
|
|
6
|
+
FunctionBuilder,
|
|
7
|
+
type ScheduleExpression,
|
|
8
|
+
} from '@geekmidas/api/constructs';
|
|
9
|
+
import { e } from '@geekmidas/api/server';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a temporary directory for testing
|
|
14
|
+
*/
|
|
15
|
+
export async function createTempDir(prefix = 'cli-test-'): Promise<string> {
|
|
16
|
+
const tempPath = join(
|
|
17
|
+
tmpdir(),
|
|
18
|
+
`${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
19
|
+
);
|
|
20
|
+
await mkdir(tempPath, { recursive: true });
|
|
21
|
+
return tempPath;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Cleans up a directory
|
|
26
|
+
*/
|
|
27
|
+
export async function cleanupDir(path: string): Promise<void> {
|
|
28
|
+
try {
|
|
29
|
+
await rm(path, { recursive: true, force: true });
|
|
30
|
+
} catch (error) {
|
|
31
|
+
// Ignore errors during cleanup
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a test file with content
|
|
37
|
+
*/
|
|
38
|
+
export async function createTestFile(
|
|
39
|
+
dir: string,
|
|
40
|
+
filename: string,
|
|
41
|
+
content: string,
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
const filePath = join(dir, filename);
|
|
44
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
45
|
+
await writeFile(filePath, content);
|
|
46
|
+
return filePath;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a mock endpoint file with real endpoint construct
|
|
51
|
+
*/
|
|
52
|
+
export async function createMockEndpointFile(
|
|
53
|
+
dir: string,
|
|
54
|
+
filename: string,
|
|
55
|
+
exportName: string,
|
|
56
|
+
path: string = '/test',
|
|
57
|
+
method: string = 'GET',
|
|
58
|
+
): Promise<string> {
|
|
59
|
+
const content = `
|
|
60
|
+
import { e } from '@geekmidas/api/server';
|
|
61
|
+
import { z } from 'zod';
|
|
62
|
+
|
|
63
|
+
export const ${exportName} = e
|
|
64
|
+
.${method.toLowerCase()}('${path}')
|
|
65
|
+
.output(z.object({ message: z.string() }))
|
|
66
|
+
.handle(async () => ({ message: 'Hello from ${exportName}' }));
|
|
67
|
+
`;
|
|
68
|
+
return createTestFile(dir, filename, content);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a mock function file with real function construct
|
|
73
|
+
*/
|
|
74
|
+
export async function createMockFunctionFile(
|
|
75
|
+
dir: string,
|
|
76
|
+
filename: string,
|
|
77
|
+
exportName: string,
|
|
78
|
+
timeout = 30,
|
|
79
|
+
): Promise<string> {
|
|
80
|
+
const content = `
|
|
81
|
+
import { FunctionBuilder } from '@geekmidas/api/constructs';
|
|
82
|
+
import { z } from 'zod';
|
|
83
|
+
|
|
84
|
+
export const ${exportName} = new FunctionBuilder()
|
|
85
|
+
.input(z.object({ name: z.string() }))
|
|
86
|
+
.output(z.object({ greeting: z.string() }))
|
|
87
|
+
.timeout(${timeout})
|
|
88
|
+
.handle(async ({ input }) => ({ greeting: \`Hello, \${input.name}!\` }));
|
|
89
|
+
`;
|
|
90
|
+
return createTestFile(dir, filename, content);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates a mock cron file with real cron construct
|
|
95
|
+
*/
|
|
96
|
+
export async function createMockCronFile(
|
|
97
|
+
dir: string,
|
|
98
|
+
filename: string,
|
|
99
|
+
exportName: string,
|
|
100
|
+
schedule = 'rate(1 hour)',
|
|
101
|
+
): Promise<string> {
|
|
102
|
+
const content = `
|
|
103
|
+
import { CronBuilder } from '@geekmidas/api/constructs';
|
|
104
|
+
import { z } from 'zod';
|
|
105
|
+
|
|
106
|
+
export const ${exportName} = new CronBuilder()
|
|
107
|
+
.schedule('${schedule}')
|
|
108
|
+
.output(z.object({ processed: z.number() }))
|
|
109
|
+
.handle(async () => {
|
|
110
|
+
console.log('Running cron job: ${exportName}');
|
|
111
|
+
return { processed: 10 };
|
|
112
|
+
});
|
|
113
|
+
`;
|
|
114
|
+
return createTestFile(dir, filename, content);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Helper functions to create real constructs for testing
|
|
119
|
+
*/
|
|
120
|
+
export function createTestEndpoint(path: string, method: HttpMethod = 'GET') {
|
|
121
|
+
const m = method.toLowerCase() as Lowercase<HttpMethod>;
|
|
122
|
+
const builder = e[m](path);
|
|
123
|
+
builder.output(z.object({ message: z.string() }));
|
|
124
|
+
return builder.handle(async () => ({ message: `Hello from ${path}` }));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function createTestFunction(timeout: number = 30) {
|
|
128
|
+
const builder = new FunctionBuilder();
|
|
129
|
+
builder.input(z.object({ name: z.string() }));
|
|
130
|
+
builder.output(z.object({ greeting: z.string() }));
|
|
131
|
+
builder.timeout(timeout);
|
|
132
|
+
return builder.handle(async ({ input }: any) => ({ greeting: `Hello, ${input.name}!` }));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function createTestCron(
|
|
136
|
+
schedule: ScheduleExpression = 'rate(1 hour)',
|
|
137
|
+
timeout: number = 30,
|
|
138
|
+
) {
|
|
139
|
+
const builder = new CronBuilder();
|
|
140
|
+
builder.schedule(schedule);
|
|
141
|
+
builder.output(z.object({ processed: z.number() }));
|
|
142
|
+
builder.timeout(timeout);
|
|
143
|
+
return builder.handle(async () => {
|
|
144
|
+
return { processed: 10 };
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a mock build context
|
|
150
|
+
*/
|
|
151
|
+
export function createMockBuildContext() {
|
|
152
|
+
return {
|
|
153
|
+
envParserPath: './env',
|
|
154
|
+
envParserImportPattern: 'envParser',
|
|
155
|
+
loggerPath: './logger',
|
|
156
|
+
loggerImportPattern: 'logger',
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Waits for a condition to be true
|
|
162
|
+
*/
|
|
163
|
+
export async function waitFor(
|
|
164
|
+
condition: () => boolean,
|
|
165
|
+
timeout = 5000,
|
|
166
|
+
interval = 100,
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
const start = Date.now();
|
|
169
|
+
while (!condition() && Date.now() - start < timeout) {
|
|
170
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
171
|
+
}
|
|
172
|
+
if (!condition()) {
|
|
173
|
+
throw new Error('Timeout waiting for condition');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
import { dirname } from 'node:path';
|
|
178
|
+
import type { HttpMethod } from '../../../api/src/constructs/types';
|