@geekmidas/cli 0.0.12 → 0.0.14

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/dist/cli.cjs CHANGED
@@ -1,6 +1,95 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env -S npx tsx
2
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
3
  require('./config-D8AyiwBU.cjs');
3
4
  require('./loadEndpoints-Dh-dSqZX.cjs');
4
- require('./build-CTKUZTHx.cjs');
5
- require('./cli-DLypHuNF.cjs');
6
- require('./openapi-DrPYAlJ_.cjs');
5
+ const require_build = require('./build-CTKUZTHx.cjs');
6
+ const require_openapi_react_query = require('./openapi-react-query-C1JLYUOs.cjs');
7
+ const require_openapi = require('./openapi-DrPYAlJ_.cjs');
8
+ const commander = require_chunk.__toESM(require("commander"));
9
+
10
+ //#region package.json
11
+ var name = "@geekmidas/cli";
12
+ var version = "0.0.14";
13
+ var private$1 = false;
14
+ var type = "module";
15
+ var bin = { "gkm": "./dist/cli.cjs" };
16
+ var publishConfig = {
17
+ "registry": "https://registry.npmjs.org/",
18
+ "access": "public"
19
+ };
20
+ var dependencies = {
21
+ "commander": "~14.0.0",
22
+ "lodash.get": "~4.4.2",
23
+ "lodash.set": "~4.3.2",
24
+ "zod": "~3.25.67",
25
+ "fast-glob": "~3.3.3",
26
+ "@geekmidas/api": "workspace:*"
27
+ };
28
+ var devDependencies = {
29
+ "@types/lodash.get": "~4.4.9",
30
+ "@types/lodash.set": "~4.3.9"
31
+ };
32
+ var package_default = {
33
+ name,
34
+ version,
35
+ private: private$1,
36
+ type,
37
+ bin,
38
+ publishConfig,
39
+ dependencies,
40
+ devDependencies
41
+ };
42
+
43
+ //#endregion
44
+ //#region src/cli.ts
45
+ const program = new commander.Command();
46
+ program.name("gkm").description("GeekMidas backend framework CLI").version(package_default.version).option("--cwd <path>", "Change working directory");
47
+ program.command("build").description("Build API handlers from endpoints").option("--providers <providers>", "Target providers for generated handlers (comma-separated)", "aws-apigatewayv1").action(async (options) => {
48
+ try {
49
+ const globalOptions = program.opts();
50
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
51
+ const providerList = [...new Set(options.providers.split(",").map((p) => p.trim()))];
52
+ await require_build.buildCommand({ providers: providerList });
53
+ } catch (error) {
54
+ console.error("Build failed:", error.message);
55
+ process.exit(1);
56
+ }
57
+ });
58
+ program.command("cron").description("Manage cron jobs").action(() => {
59
+ const globalOptions = program.opts();
60
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
61
+ process.stdout.write("Cron management - coming soon\n");
62
+ });
63
+ program.command("function").description("Manage serverless functions").action(() => {
64
+ const globalOptions = program.opts();
65
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
66
+ process.stdout.write("Serverless function management - coming soon\n");
67
+ });
68
+ program.command("api").description("Manage REST API endpoints").action(() => {
69
+ const globalOptions = program.opts();
70
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
71
+ process.stdout.write("REST API management - coming soon\n");
72
+ });
73
+ program.command("openapi").description("Generate OpenAPI 3.0 specification from endpoints").option("--output <path>", "Output file path for the OpenAPI spec", "openapi.json").action(async (options) => {
74
+ try {
75
+ const globalOptions = program.opts();
76
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
77
+ await require_openapi.openapiCommand(options);
78
+ } catch (error) {
79
+ console.error("OpenAPI generation failed:", error.message);
80
+ process.exit(1);
81
+ }
82
+ });
83
+ program.command("generate:react-query").description("Generate React Query hooks from OpenAPI specification").option("--input <path>", "Input OpenAPI spec file path", "openapi.json").option("--output <path>", "Output file path for generated hooks", "src/api/hooks.ts").option("--name <name>", "API name prefix for generated code", "API").action(async (options) => {
84
+ try {
85
+ const globalOptions = program.opts();
86
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
87
+ await require_openapi_react_query.generateReactQueryCommand(options);
88
+ } catch (error) {
89
+ console.error("React Query generation failed:", error.message);
90
+ process.exit(1);
91
+ }
92
+ });
93
+ program.parse();
94
+
95
+ //#endregion
package/dist/cli.mjs CHANGED
@@ -1,6 +1,94 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env -S npx tsx
2
2
  import "./config-DV1Lwdkx.mjs";
3
3
  import "./loadEndpoints-DKaw6Eqm.mjs";
4
- import "./build-DgeiXkH-.mjs";
5
- import "./cli-BuIVmCrJ.mjs";
6
- import "./openapi-DgLItZw-.mjs";
4
+ import { buildCommand } from "./build-DgeiXkH-.mjs";
5
+ import { generateReactQueryCommand } from "./openapi-react-query-DpT3XHFC.mjs";
6
+ import { openapiCommand } from "./openapi-DgLItZw-.mjs";
7
+ import { Command } from "commander";
8
+
9
+ //#region package.json
10
+ var name = "@geekmidas/cli";
11
+ var version = "0.0.14";
12
+ var private$1 = false;
13
+ var type = "module";
14
+ var bin = { "gkm": "./dist/cli.cjs" };
15
+ var publishConfig = {
16
+ "registry": "https://registry.npmjs.org/",
17
+ "access": "public"
18
+ };
19
+ var dependencies = {
20
+ "commander": "~14.0.0",
21
+ "lodash.get": "~4.4.2",
22
+ "lodash.set": "~4.3.2",
23
+ "zod": "~3.25.67",
24
+ "fast-glob": "~3.3.3",
25
+ "@geekmidas/api": "workspace:*"
26
+ };
27
+ var devDependencies = {
28
+ "@types/lodash.get": "~4.4.9",
29
+ "@types/lodash.set": "~4.3.9"
30
+ };
31
+ var package_default = {
32
+ name,
33
+ version,
34
+ private: private$1,
35
+ type,
36
+ bin,
37
+ publishConfig,
38
+ dependencies,
39
+ devDependencies
40
+ };
41
+
42
+ //#endregion
43
+ //#region src/cli.ts
44
+ const program = new Command();
45
+ program.name("gkm").description("GeekMidas backend framework CLI").version(package_default.version).option("--cwd <path>", "Change working directory");
46
+ program.command("build").description("Build API handlers from endpoints").option("--providers <providers>", "Target providers for generated handlers (comma-separated)", "aws-apigatewayv1").action(async (options) => {
47
+ try {
48
+ const globalOptions = program.opts();
49
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
50
+ const providerList = [...new Set(options.providers.split(",").map((p) => p.trim()))];
51
+ await buildCommand({ providers: providerList });
52
+ } catch (error) {
53
+ console.error("Build failed:", error.message);
54
+ process.exit(1);
55
+ }
56
+ });
57
+ program.command("cron").description("Manage cron jobs").action(() => {
58
+ const globalOptions = program.opts();
59
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
60
+ process.stdout.write("Cron management - coming soon\n");
61
+ });
62
+ program.command("function").description("Manage serverless functions").action(() => {
63
+ const globalOptions = program.opts();
64
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
65
+ process.stdout.write("Serverless function management - coming soon\n");
66
+ });
67
+ program.command("api").description("Manage REST API endpoints").action(() => {
68
+ const globalOptions = program.opts();
69
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
70
+ process.stdout.write("REST API management - coming soon\n");
71
+ });
72
+ program.command("openapi").description("Generate OpenAPI 3.0 specification from endpoints").option("--output <path>", "Output file path for the OpenAPI spec", "openapi.json").action(async (options) => {
73
+ try {
74
+ const globalOptions = program.opts();
75
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
76
+ await openapiCommand(options);
77
+ } catch (error) {
78
+ console.error("OpenAPI generation failed:", error.message);
79
+ process.exit(1);
80
+ }
81
+ });
82
+ program.command("generate:react-query").description("Generate React Query hooks from OpenAPI specification").option("--input <path>", "Input OpenAPI spec file path", "openapi.json").option("--output <path>", "Output file path for generated hooks", "src/api/hooks.ts").option("--name <name>", "API name prefix for generated code", "API").action(async (options) => {
83
+ try {
84
+ const globalOptions = program.opts();
85
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
86
+ await generateReactQueryCommand(options);
87
+ } catch (error) {
88
+ console.error("React Query generation failed:", error.message);
89
+ process.exit(1);
90
+ }
91
+ });
92
+ program.parse();
93
+
94
+ //#endregion
@@ -0,0 +1,171 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
3
+ const node_child_process = require_chunk.__toESM(require("node:child_process"));
4
+ const node_fs = require_chunk.__toESM(require("node:fs"));
5
+ const node_path = require_chunk.__toESM(require("node:path"));
6
+ const node_util = require_chunk.__toESM(require("node:util"));
7
+
8
+ //#region src/openapi-react-query.ts
9
+ const execAsync = (0, node_util.promisify)(node_child_process.exec);
10
+ async function generateReactQueryCommand(options = {}) {
11
+ const logger = console;
12
+ try {
13
+ const inputPath = options.input || (0, node_path.join)(process.cwd(), "openapi.json");
14
+ if (!(0, node_fs.existsSync)(inputPath)) throw new Error(`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`);
15
+ const specContent = await (0, node_fs_promises.readFile)(inputPath, "utf-8");
16
+ const spec = JSON.parse(specContent);
17
+ const outputDir = (0, node_path.dirname)(options.output || (0, node_path.join)(process.cwd(), "src", "api", "hooks.ts"));
18
+ const typesPath = (0, node_path.join)(outputDir, "openapi-types.d.ts");
19
+ logger.log("Generating TypeScript types from OpenAPI spec...");
20
+ try {
21
+ await execAsync(`npx openapi-typescript "${inputPath}" -o "${typesPath}"`, { cwd: process.cwd() });
22
+ logger.log(`TypeScript types generated: ${typesPath}`);
23
+ } catch (error) {
24
+ logger.warn("Could not generate types with openapi-typescript. Install it for better type inference.");
25
+ logger.warn("Run: npm install -D openapi-typescript");
26
+ await (0, node_fs_promises.writeFile)(typesPath, `// Auto-generated placeholder types
27
+ export interface paths {
28
+ [path: string]: {
29
+ [method: string]: {
30
+ operationId?: string;
31
+ parameters?: any;
32
+ requestBody?: any;
33
+ responses?: any;
34
+ };
35
+ };
36
+ }
37
+ `);
38
+ }
39
+ const operations = extractOperations(spec);
40
+ const code = generateReactQueryCode(spec, operations, options.name || "API");
41
+ const outputPath = options.output || (0, node_path.join)(process.cwd(), "src", "api", "hooks.ts");
42
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(outputPath), { recursive: true });
43
+ await (0, node_fs_promises.writeFile)(outputPath, code);
44
+ logger.log(`React Query hooks generated: ${outputPath}`);
45
+ logger.log(`Generated ${operations.length} hooks`);
46
+ } catch (error) {
47
+ throw new Error(`React Query generation failed: ${error.message}`);
48
+ }
49
+ }
50
+ function extractOperations(spec) {
51
+ const operations = [];
52
+ Object.entries(spec.paths).forEach(([path, methods]) => {
53
+ Object.entries(methods).forEach(([method, operation]) => {
54
+ if (operation.operationId) operations.push({
55
+ operationId: operation.operationId,
56
+ path,
57
+ method: method.toUpperCase(),
58
+ endpoint: `${method.toUpperCase()} ${path}`,
59
+ parameters: operation.parameters,
60
+ requestBody: !!operation.requestBody,
61
+ responseType: extractResponseType(operation)
62
+ });
63
+ });
64
+ });
65
+ return operations;
66
+ }
67
+ function extractResponseType(operation) {
68
+ const responses = operation.responses;
69
+ if (!responses) return "unknown";
70
+ const successResponse = responses["200"] || responses["201"];
71
+ if (!successResponse?.content?.["application/json"]?.schema) return "unknown";
72
+ const schema = successResponse.content["application/json"].schema;
73
+ return schemaToTypeString(schema);
74
+ }
75
+ function schemaToTypeString(schema) {
76
+ if (!schema) return "unknown";
77
+ switch (schema.type) {
78
+ case "string": return "string";
79
+ case "number":
80
+ case "integer": return "number";
81
+ case "boolean": return "boolean";
82
+ case "array": return `Array<${schemaToTypeString(schema.items)}>`;
83
+ case "object":
84
+ if (schema.properties) {
85
+ const props = Object.entries(schema.properties).map(([key, value]) => `${key}: ${schemaToTypeString(value)}`).join("; ");
86
+ return `{ ${props} }`;
87
+ }
88
+ return "Record<string, unknown>";
89
+ default: return "unknown";
90
+ }
91
+ }
92
+ function generateReactQueryCode(spec, operations, apiName) {
93
+ const imports = `import { createTypedQueryClient } from '@geekmidas/api/client';
94
+ import type { paths } from './openapi-types';
95
+
96
+ // Create typed query client
97
+ export const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({
98
+ baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',
99
+ });
100
+
101
+ // Export individual hooks for better DX
102
+ `;
103
+ const queryHooks = operations.filter((op) => op.method === "GET").map((op) => generateQueryHook(op, apiName)).join("\n\n");
104
+ const mutationHooks = operations.filter((op) => op.method !== "GET").map((op) => generateMutationHook(op, apiName)).join("\n\n");
105
+ const typeExports = generateTypeExports(operations);
106
+ return `${imports}
107
+ // Query Hooks
108
+ ${queryHooks}
109
+
110
+ // Mutation Hooks
111
+ ${mutationHooks}
112
+
113
+ // Type exports for convenience
114
+ ${typeExports}
115
+
116
+ // Re-export the api for advanced usage
117
+ export { ${apiName.toLowerCase()} };
118
+ `;
119
+ }
120
+ function generateQueryHook(op, apiName) {
121
+ const hookName = `use${capitalize(op.operationId)}`;
122
+ const endpoint = op.endpoint;
123
+ const hasParams = op.parameters?.some((p) => p.in === "path");
124
+ const hasQuery = op.parameters?.some((p) => p.in === "query");
125
+ let params = "";
126
+ let args = "";
127
+ if (hasParams || hasQuery) {
128
+ const paramParts = [];
129
+ if (hasParams) {
130
+ const pathParams = op.parameters?.filter((p) => p.in === "path").map((p) => p.name) || [];
131
+ paramParts.push(`params: { ${pathParams.map((p) => `${p}: string`).join("; ")} }`);
132
+ }
133
+ if (hasQuery) paramParts.push(`query?: Record<string, any>`);
134
+ params = `config: { ${paramParts.join("; ")} }, `;
135
+ args = ", config";
136
+ }
137
+ return `export const ${hookName} = (
138
+ ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]
139
+ ) => {
140
+ return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);
141
+ };`;
142
+ }
143
+ function generateMutationHook(op, apiName) {
144
+ const hookName = `use${capitalize(op.operationId)}`;
145
+ const endpoint = op.endpoint;
146
+ return `export const ${hookName} = (
147
+ options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]
148
+ ) => {
149
+ return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);
150
+ };`;
151
+ }
152
+ function generateTypeExports(operations) {
153
+ const exports$1 = operations.map((op) => {
154
+ const typeName = capitalize(op.operationId);
155
+ const isQuery = op.method === "GET";
156
+ if (isQuery) return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;
157
+ else return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;
158
+ });
159
+ return exports$1.join("\n");
160
+ }
161
+ function capitalize(str) {
162
+ return str.charAt(0).toUpperCase() + str.slice(1);
163
+ }
164
+
165
+ //#endregion
166
+ Object.defineProperty(exports, 'generateReactQueryCommand', {
167
+ enumerable: true,
168
+ get: function () {
169
+ return generateReactQueryCommand;
170
+ }
171
+ });
@@ -0,0 +1,165 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { exec } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { promisify } from "node:util";
6
+
7
+ //#region src/openapi-react-query.ts
8
+ const execAsync = promisify(exec);
9
+ async function generateReactQueryCommand(options = {}) {
10
+ const logger = console;
11
+ try {
12
+ const inputPath = options.input || join(process.cwd(), "openapi.json");
13
+ if (!existsSync(inputPath)) throw new Error(`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`);
14
+ const specContent = await readFile(inputPath, "utf-8");
15
+ const spec = JSON.parse(specContent);
16
+ const outputDir = dirname(options.output || join(process.cwd(), "src", "api", "hooks.ts"));
17
+ const typesPath = join(outputDir, "openapi-types.d.ts");
18
+ logger.log("Generating TypeScript types from OpenAPI spec...");
19
+ try {
20
+ await execAsync(`npx openapi-typescript "${inputPath}" -o "${typesPath}"`, { cwd: process.cwd() });
21
+ logger.log(`TypeScript types generated: ${typesPath}`);
22
+ } catch (error) {
23
+ logger.warn("Could not generate types with openapi-typescript. Install it for better type inference.");
24
+ logger.warn("Run: npm install -D openapi-typescript");
25
+ await writeFile(typesPath, `// Auto-generated placeholder types
26
+ export interface paths {
27
+ [path: string]: {
28
+ [method: string]: {
29
+ operationId?: string;
30
+ parameters?: any;
31
+ requestBody?: any;
32
+ responses?: any;
33
+ };
34
+ };
35
+ }
36
+ `);
37
+ }
38
+ const operations = extractOperations(spec);
39
+ const code = generateReactQueryCode(spec, operations, options.name || "API");
40
+ const outputPath = options.output || join(process.cwd(), "src", "api", "hooks.ts");
41
+ await mkdir(dirname(outputPath), { recursive: true });
42
+ await writeFile(outputPath, code);
43
+ logger.log(`React Query hooks generated: ${outputPath}`);
44
+ logger.log(`Generated ${operations.length} hooks`);
45
+ } catch (error) {
46
+ throw new Error(`React Query generation failed: ${error.message}`);
47
+ }
48
+ }
49
+ function extractOperations(spec) {
50
+ const operations = [];
51
+ Object.entries(spec.paths).forEach(([path, methods]) => {
52
+ Object.entries(methods).forEach(([method, operation]) => {
53
+ if (operation.operationId) operations.push({
54
+ operationId: operation.operationId,
55
+ path,
56
+ method: method.toUpperCase(),
57
+ endpoint: `${method.toUpperCase()} ${path}`,
58
+ parameters: operation.parameters,
59
+ requestBody: !!operation.requestBody,
60
+ responseType: extractResponseType(operation)
61
+ });
62
+ });
63
+ });
64
+ return operations;
65
+ }
66
+ function extractResponseType(operation) {
67
+ const responses = operation.responses;
68
+ if (!responses) return "unknown";
69
+ const successResponse = responses["200"] || responses["201"];
70
+ if (!successResponse?.content?.["application/json"]?.schema) return "unknown";
71
+ const schema = successResponse.content["application/json"].schema;
72
+ return schemaToTypeString(schema);
73
+ }
74
+ function schemaToTypeString(schema) {
75
+ if (!schema) return "unknown";
76
+ switch (schema.type) {
77
+ case "string": return "string";
78
+ case "number":
79
+ case "integer": return "number";
80
+ case "boolean": return "boolean";
81
+ case "array": return `Array<${schemaToTypeString(schema.items)}>`;
82
+ case "object":
83
+ if (schema.properties) {
84
+ const props = Object.entries(schema.properties).map(([key, value]) => `${key}: ${schemaToTypeString(value)}`).join("; ");
85
+ return `{ ${props} }`;
86
+ }
87
+ return "Record<string, unknown>";
88
+ default: return "unknown";
89
+ }
90
+ }
91
+ function generateReactQueryCode(spec, operations, apiName) {
92
+ const imports = `import { createTypedQueryClient } from '@geekmidas/api/client';
93
+ import type { paths } from './openapi-types';
94
+
95
+ // Create typed query client
96
+ export const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({
97
+ baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',
98
+ });
99
+
100
+ // Export individual hooks for better DX
101
+ `;
102
+ const queryHooks = operations.filter((op) => op.method === "GET").map((op) => generateQueryHook(op, apiName)).join("\n\n");
103
+ const mutationHooks = operations.filter((op) => op.method !== "GET").map((op) => generateMutationHook(op, apiName)).join("\n\n");
104
+ const typeExports = generateTypeExports(operations);
105
+ return `${imports}
106
+ // Query Hooks
107
+ ${queryHooks}
108
+
109
+ // Mutation Hooks
110
+ ${mutationHooks}
111
+
112
+ // Type exports for convenience
113
+ ${typeExports}
114
+
115
+ // Re-export the api for advanced usage
116
+ export { ${apiName.toLowerCase()} };
117
+ `;
118
+ }
119
+ function generateQueryHook(op, apiName) {
120
+ const hookName = `use${capitalize(op.operationId)}`;
121
+ const endpoint = op.endpoint;
122
+ const hasParams = op.parameters?.some((p) => p.in === "path");
123
+ const hasQuery = op.parameters?.some((p) => p.in === "query");
124
+ let params = "";
125
+ let args = "";
126
+ if (hasParams || hasQuery) {
127
+ const paramParts = [];
128
+ if (hasParams) {
129
+ const pathParams = op.parameters?.filter((p) => p.in === "path").map((p) => p.name) || [];
130
+ paramParts.push(`params: { ${pathParams.map((p) => `${p}: string`).join("; ")} }`);
131
+ }
132
+ if (hasQuery) paramParts.push(`query?: Record<string, any>`);
133
+ params = `config: { ${paramParts.join("; ")} }, `;
134
+ args = ", config";
135
+ }
136
+ return `export const ${hookName} = (
137
+ ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]
138
+ ) => {
139
+ return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);
140
+ };`;
141
+ }
142
+ function generateMutationHook(op, apiName) {
143
+ const hookName = `use${capitalize(op.operationId)}`;
144
+ const endpoint = op.endpoint;
145
+ return `export const ${hookName} = (
146
+ options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]
147
+ ) => {
148
+ return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);
149
+ };`;
150
+ }
151
+ function generateTypeExports(operations) {
152
+ const exports = operations.map((op) => {
153
+ const typeName = capitalize(op.operationId);
154
+ const isQuery = op.method === "GET";
155
+ if (isQuery) return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;
156
+ else return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;
157
+ });
158
+ return exports.join("\n");
159
+ }
160
+ function capitalize(str) {
161
+ return str.charAt(0).toUpperCase() + str.slice(1);
162
+ }
163
+
164
+ //#endregion
165
+ export { generateReactQueryCommand };
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env -S npx tsx
2
+ const require_openapi_react_query = require('./openapi-react-query-C1JLYUOs.cjs');
3
+
4
+ exports.generateReactQueryCommand = require_openapi_react_query.generateReactQueryCommand;
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env -S npx tsx
2
+ import { generateReactQueryCommand } from "./openapi-react-query-DpT3XHFC.mjs";
3
+
4
+ export { generateReactQueryCommand };
package/package.json CHANGED
@@ -1,17 +1,10 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
7
- "gkm": "./src/index.ts"
8
- },
9
- "exports": {
10
- ".": {
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.cjs",
13
- "types": "./src/index.ts"
14
- }
7
+ "gkm": "./dist/cli.cjs"
15
8
  },
16
9
  "publishConfig": {
17
10
  "registry": "https://registry.npmjs.org/",
@@ -23,7 +16,7 @@
23
16
  "lodash.set": "~4.3.2",
24
17
  "zod": "~3.25.67",
25
18
  "fast-glob": "~3.3.3",
26
- "@geekmidas/api": "0.0.26"
19
+ "@geekmidas/api": "0.0.31"
27
20
  },
28
21
  "devDependencies": {
29
22
  "@types/lodash.get": "~4.4.9",
package/src/cli.ts CHANGED
@@ -1,10 +1,11 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env -S npx tsx
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import pkg from '../package.json' assert { type: 'json' };
5
- import { buildCommand } from './build.js';
6
- import { openapiCommand } from './openapi.js';
7
- import type { Provider } from './types.js';
5
+ import { buildCommand } from './build.ts';
6
+ import { generateReactQueryCommand } from './openapi-react-query.ts';
7
+ import { openapiCommand } from './openapi.ts';
8
+ import type { Provider } from './types.ts';
8
9
 
9
10
  const program = new Command();
10
11
 
@@ -92,4 +93,32 @@ program
92
93
  }
93
94
  });
94
95
 
96
+ program
97
+ .command('generate:react-query')
98
+ .description('Generate React Query hooks from OpenAPI specification')
99
+ .option('--input <path>', 'Input OpenAPI spec file path', 'openapi.json')
100
+ .option(
101
+ '--output <path>',
102
+ 'Output file path for generated hooks',
103
+ 'src/api/hooks.ts',
104
+ )
105
+ .option('--name <name>', 'API name prefix for generated code', 'API')
106
+ .action(
107
+ async (options: { input?: string; output?: string; name?: string }) => {
108
+ try {
109
+ const globalOptions = program.opts();
110
+ if (globalOptions.cwd) {
111
+ process.chdir(globalOptions.cwd);
112
+ }
113
+ await generateReactQueryCommand(options);
114
+ } catch (error) {
115
+ console.error(
116
+ 'React Query generation failed:',
117
+ (error as Error).message,
118
+ );
119
+ process.exit(1);
120
+ }
121
+ },
122
+ );
123
+
95
124
  program.parse();
@@ -0,0 +1,287 @@
1
+ #!/usr/bin/env -S npx tsx
2
+
3
+ import { exec } from 'node:child_process';
4
+ import { existsSync } from 'node:fs';
5
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
6
+ import { dirname, join } from 'node:path';
7
+ import { promisify } from 'node:util';
8
+
9
+ const execAsync = promisify(exec);
10
+
11
+ interface ReactQueryOptions {
12
+ input?: string;
13
+ output?: string;
14
+ name?: string;
15
+ }
16
+
17
+ interface OpenAPISpec {
18
+ openapi: string;
19
+ info?: {
20
+ title?: string;
21
+ version?: string;
22
+ };
23
+ paths: Record<string, Record<string, any>>;
24
+ }
25
+
26
+ export async function generateReactQueryCommand(
27
+ options: ReactQueryOptions = {},
28
+ ): Promise<void> {
29
+ const logger = console;
30
+
31
+ try {
32
+ // Read OpenAPI spec
33
+ const inputPath = options.input || join(process.cwd(), 'openapi.json');
34
+
35
+ if (!existsSync(inputPath)) {
36
+ throw new Error(
37
+ `OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`,
38
+ );
39
+ }
40
+
41
+ const specContent = await readFile(inputPath, 'utf-8');
42
+ const spec: OpenAPISpec = JSON.parse(specContent);
43
+
44
+ // Generate TypeScript types from OpenAPI spec
45
+ const outputDir = dirname(
46
+ options.output || join(process.cwd(), 'src', 'api', 'hooks.ts'),
47
+ );
48
+ const typesPath = join(outputDir, 'openapi-types.d.ts');
49
+
50
+ logger.log('Generating TypeScript types from OpenAPI spec...');
51
+
52
+ try {
53
+ // Use npx to run openapi-typescript
54
+ await execAsync(
55
+ `npx openapi-typescript "${inputPath}" -o "${typesPath}"`,
56
+ { cwd: process.cwd() },
57
+ );
58
+ logger.log(`TypeScript types generated: ${typesPath}`);
59
+ } catch (error) {
60
+ logger.warn(
61
+ 'Could not generate types with openapi-typescript. Install it for better type inference.',
62
+ );
63
+ logger.warn('Run: npm install -D openapi-typescript');
64
+
65
+ // Generate basic types file
66
+ await writeFile(
67
+ typesPath,
68
+ `// Auto-generated placeholder types
69
+ export interface paths {
70
+ [path: string]: {
71
+ [method: string]: {
72
+ operationId?: string;
73
+ parameters?: any;
74
+ requestBody?: any;
75
+ responses?: any;
76
+ };
77
+ };
78
+ }
79
+ `,
80
+ );
81
+ }
82
+
83
+ // Extract operation info
84
+ const operations = extractOperations(spec);
85
+
86
+ // Generate TypeScript code
87
+ const code = generateReactQueryCode(
88
+ spec,
89
+ operations,
90
+ options.name || 'API',
91
+ );
92
+
93
+ // Write output
94
+ const outputPath =
95
+ options.output || join(process.cwd(), 'src', 'api', 'hooks.ts');
96
+ await mkdir(dirname(outputPath), { recursive: true });
97
+ await writeFile(outputPath, code);
98
+
99
+ logger.log(`React Query hooks generated: ${outputPath}`);
100
+ logger.log(`Generated ${operations.length} hooks`);
101
+ } catch (error) {
102
+ throw new Error(
103
+ `React Query generation failed: ${(error as Error).message}`,
104
+ );
105
+ }
106
+ }
107
+
108
+ interface OperationInfo {
109
+ operationId: string;
110
+ path: string;
111
+ method: string;
112
+ endpoint: string; // Full endpoint like 'GET /users/{id}'
113
+ parameters?: Array<{ name: string; in: string; required?: boolean }>;
114
+ requestBody?: boolean;
115
+ responseType?: string;
116
+ }
117
+
118
+ function extractOperations(spec: OpenAPISpec): OperationInfo[] {
119
+ const operations: OperationInfo[] = [];
120
+
121
+ Object.entries(spec.paths).forEach(([path, methods]) => {
122
+ Object.entries(methods).forEach(([method, operation]) => {
123
+ if (operation.operationId) {
124
+ operations.push({
125
+ operationId: operation.operationId,
126
+ path,
127
+ method: method.toUpperCase(),
128
+ endpoint: `${method.toUpperCase()} ${path}`,
129
+ parameters: operation.parameters,
130
+ requestBody: !!operation.requestBody,
131
+ responseType: extractResponseType(operation),
132
+ });
133
+ }
134
+ });
135
+ });
136
+
137
+ return operations;
138
+ }
139
+
140
+ function extractResponseType(operation: any): string {
141
+ const responses = operation.responses;
142
+ if (!responses) return 'unknown';
143
+
144
+ const successResponse = responses['200'] || responses['201'];
145
+ if (!successResponse?.content?.['application/json']?.schema) {
146
+ return 'unknown';
147
+ }
148
+
149
+ // Basic type inference from schema
150
+ const schema = successResponse.content['application/json'].schema;
151
+ return schemaToTypeString(schema);
152
+ }
153
+
154
+ function schemaToTypeString(schema: any): string {
155
+ if (!schema) return 'unknown';
156
+
157
+ switch (schema.type) {
158
+ case 'string':
159
+ return 'string';
160
+ case 'number':
161
+ case 'integer':
162
+ return 'number';
163
+ case 'boolean':
164
+ return 'boolean';
165
+ case 'array':
166
+ return `Array<${schemaToTypeString(schema.items)}>`;
167
+ case 'object':
168
+ if (schema.properties) {
169
+ const props = Object.entries(schema.properties)
170
+ .map(
171
+ ([key, value]: [string, any]) =>
172
+ `${key}: ${schemaToTypeString(value)}`,
173
+ )
174
+ .join('; ');
175
+ return `{ ${props} }`;
176
+ }
177
+ return 'Record<string, unknown>';
178
+ default:
179
+ return 'unknown';
180
+ }
181
+ }
182
+
183
+ function generateReactQueryCode(
184
+ spec: OpenAPISpec,
185
+ operations: OperationInfo[],
186
+ apiName: string,
187
+ ): string {
188
+ const imports = `import { createTypedQueryClient } from '@geekmidas/api/client';
189
+ import type { paths } from './openapi-types';
190
+
191
+ // Create typed query client
192
+ export const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({
193
+ baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',
194
+ });
195
+
196
+ // Export individual hooks for better DX
197
+ `;
198
+
199
+ const queryHooks = operations
200
+ .filter((op) => op.method === 'GET')
201
+ .map((op) => generateQueryHook(op, apiName))
202
+ .join('\n\n');
203
+
204
+ const mutationHooks = operations
205
+ .filter((op) => op.method !== 'GET')
206
+ .map((op) => generateMutationHook(op, apiName))
207
+ .join('\n\n');
208
+
209
+ const typeExports = generateTypeExports(operations);
210
+
211
+ return `${imports}
212
+ // Query Hooks
213
+ ${queryHooks}
214
+
215
+ // Mutation Hooks
216
+ ${mutationHooks}
217
+
218
+ // Type exports for convenience
219
+ ${typeExports}
220
+
221
+ // Re-export the api for advanced usage
222
+ export { ${apiName.toLowerCase()} };
223
+ `;
224
+ }
225
+
226
+ function generateQueryHook(op: OperationInfo, apiName: string): string {
227
+ const hookName = `use${capitalize(op.operationId)}`;
228
+ const endpoint = op.endpoint;
229
+ const hasParams = op.parameters?.some((p) => p.in === 'path');
230
+ const hasQuery = op.parameters?.some((p) => p.in === 'query');
231
+
232
+ // Generate properly typed hook
233
+ let params = '';
234
+ let args = '';
235
+
236
+ if (hasParams || hasQuery) {
237
+ const paramParts: string[] = [];
238
+ if (hasParams) {
239
+ const pathParams =
240
+ op.parameters?.filter((p) => p.in === 'path').map((p) => p.name) || [];
241
+ paramParts.push(
242
+ `params: { ${pathParams.map((p) => `${p}: string`).join('; ')} }`,
243
+ );
244
+ }
245
+ if (hasQuery) {
246
+ paramParts.push(`query?: Record<string, any>`);
247
+ }
248
+ params = `config: { ${paramParts.join('; ')} }, `;
249
+ args = ', config';
250
+ }
251
+
252
+ return `export const ${hookName} = (
253
+ ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]
254
+ ) => {
255
+ return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);
256
+ };`;
257
+ }
258
+
259
+ function generateMutationHook(op: OperationInfo, apiName: string): string {
260
+ const hookName = `use${capitalize(op.operationId)}`;
261
+ const endpoint = op.endpoint;
262
+
263
+ return `export const ${hookName} = (
264
+ options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]
265
+ ) => {
266
+ return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);
267
+ };`;
268
+ }
269
+
270
+ function generateTypeExports(operations: OperationInfo[]): string {
271
+ const exports = operations.map((op) => {
272
+ const typeName = capitalize(op.operationId);
273
+ const isQuery = op.method === 'GET';
274
+
275
+ if (isQuery) {
276
+ return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;
277
+ } else {
278
+ return `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;
279
+ }
280
+ });
281
+
282
+ return exports.join('\n');
283
+ }
284
+
285
+ function capitalize(str: string): string {
286
+ return str.charAt(0).toUpperCase() + str.slice(1);
287
+ }
package/tsdown.config.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import { defineConfig } from 'tsdown';
2
2
 
3
- export default defineConfig({});
3
+ export default defineConfig({
4
+ dts: false,
5
+ });
@@ -1,86 +0,0 @@
1
- import { buildCommand } from "./build-DgeiXkH-.mjs";
2
- import { openapiCommand } from "./openapi-DgLItZw-.mjs";
3
- import { Command } from "commander";
4
-
5
- //#region package.json
6
- var name = "@geekmidas/cli";
7
- var version = "0.0.12";
8
- var private$1 = false;
9
- var type = "module";
10
- var bin = { "gkm": "./src/index.ts" };
11
- var exports = { ".": {
12
- "import": "./dist/index.mjs",
13
- "require": "./dist/index.cjs",
14
- "types": "./src/index.ts"
15
- } };
16
- var publishConfig = {
17
- "registry": "https://registry.npmjs.org/",
18
- "access": "public"
19
- };
20
- var dependencies = {
21
- "commander": "~14.0.0",
22
- "lodash.get": "~4.4.2",
23
- "lodash.set": "~4.3.2",
24
- "zod": "~3.25.67",
25
- "fast-glob": "~3.3.3",
26
- "@geekmidas/api": "workspace:*"
27
- };
28
- var devDependencies = {
29
- "@types/lodash.get": "~4.4.9",
30
- "@types/lodash.set": "~4.3.9"
31
- };
32
- var package_default = {
33
- name,
34
- version,
35
- private: private$1,
36
- type,
37
- bin,
38
- exports,
39
- publishConfig,
40
- dependencies,
41
- devDependencies
42
- };
43
-
44
- //#endregion
45
- //#region src/cli.ts
46
- const program = new Command();
47
- program.name("gkm").description("GeekMidas backend framework CLI").version(package_default.version).option("--cwd <path>", "Change working directory");
48
- program.command("build").description("Build API handlers from endpoints").option("--providers <providers>", "Target providers for generated handlers (comma-separated)", "aws-apigatewayv1").action(async (options) => {
49
- try {
50
- const globalOptions = program.opts();
51
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
52
- const providerList = [...new Set(options.providers.split(",").map((p) => p.trim()))];
53
- await buildCommand({ providers: providerList });
54
- } catch (error) {
55
- console.error("Build failed:", error.message);
56
- process.exit(1);
57
- }
58
- });
59
- program.command("cron").description("Manage cron jobs").action(() => {
60
- const globalOptions = program.opts();
61
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
62
- process.stdout.write("Cron management - coming soon\n");
63
- });
64
- program.command("function").description("Manage serverless functions").action(() => {
65
- const globalOptions = program.opts();
66
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
67
- process.stdout.write("Serverless function management - coming soon\n");
68
- });
69
- program.command("api").description("Manage REST API endpoints").action(() => {
70
- const globalOptions = program.opts();
71
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
72
- process.stdout.write("REST API management - coming soon\n");
73
- });
74
- program.command("openapi").description("Generate OpenAPI 3.0 specification from endpoints").option("--output <path>", "Output file path for the OpenAPI spec", "openapi.json").action(async (options) => {
75
- try {
76
- const globalOptions = program.opts();
77
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
78
- await openapiCommand(options);
79
- } catch (error) {
80
- console.error("OpenAPI generation failed:", error.message);
81
- process.exit(1);
82
- }
83
- });
84
- program.parse();
85
-
86
- //#endregion
@@ -1,87 +0,0 @@
1
- const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_build = require('./build-CTKUZTHx.cjs');
3
- const require_openapi = require('./openapi-DrPYAlJ_.cjs');
4
- const commander = require_chunk.__toESM(require("commander"));
5
-
6
- //#region package.json
7
- var name = "@geekmidas/cli";
8
- var version = "0.0.12";
9
- var private$1 = false;
10
- var type = "module";
11
- var bin = { "gkm": "./src/index.ts" };
12
- var exports$1 = { ".": {
13
- "import": "./dist/index.mjs",
14
- "require": "./dist/index.cjs",
15
- "types": "./src/index.ts"
16
- } };
17
- var publishConfig = {
18
- "registry": "https://registry.npmjs.org/",
19
- "access": "public"
20
- };
21
- var dependencies = {
22
- "commander": "~14.0.0",
23
- "lodash.get": "~4.4.2",
24
- "lodash.set": "~4.3.2",
25
- "zod": "~3.25.67",
26
- "fast-glob": "~3.3.3",
27
- "@geekmidas/api": "workspace:*"
28
- };
29
- var devDependencies = {
30
- "@types/lodash.get": "~4.4.9",
31
- "@types/lodash.set": "~4.3.9"
32
- };
33
- var package_default = {
34
- name,
35
- version,
36
- private: private$1,
37
- type,
38
- bin,
39
- exports: exports$1,
40
- publishConfig,
41
- dependencies,
42
- devDependencies
43
- };
44
-
45
- //#endregion
46
- //#region src/cli.ts
47
- const program = new commander.Command();
48
- program.name("gkm").description("GeekMidas backend framework CLI").version(package_default.version).option("--cwd <path>", "Change working directory");
49
- program.command("build").description("Build API handlers from endpoints").option("--providers <providers>", "Target providers for generated handlers (comma-separated)", "aws-apigatewayv1").action(async (options) => {
50
- try {
51
- const globalOptions = program.opts();
52
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
53
- const providerList = [...new Set(options.providers.split(",").map((p) => p.trim()))];
54
- await require_build.buildCommand({ providers: providerList });
55
- } catch (error) {
56
- console.error("Build failed:", error.message);
57
- process.exit(1);
58
- }
59
- });
60
- program.command("cron").description("Manage cron jobs").action(() => {
61
- const globalOptions = program.opts();
62
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
63
- process.stdout.write("Cron management - coming soon\n");
64
- });
65
- program.command("function").description("Manage serverless functions").action(() => {
66
- const globalOptions = program.opts();
67
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
68
- process.stdout.write("Serverless function management - coming soon\n");
69
- });
70
- program.command("api").description("Manage REST API endpoints").action(() => {
71
- const globalOptions = program.opts();
72
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
73
- process.stdout.write("REST API management - coming soon\n");
74
- });
75
- program.command("openapi").description("Generate OpenAPI 3.0 specification from endpoints").option("--output <path>", "Output file path for the OpenAPI spec", "openapi.json").action(async (options) => {
76
- try {
77
- const globalOptions = program.opts();
78
- if (globalOptions.cwd) process.chdir(globalOptions.cwd);
79
- await require_openapi.openapiCommand(options);
80
- } catch (error) {
81
- console.error("OpenAPI generation failed:", error.message);
82
- process.exit(1);
83
- }
84
- });
85
- program.parse();
86
-
87
- //#endregion
package/dist/index.cjs DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env -S npx tsx
2
- require('./config-D8AyiwBU.cjs');
3
- require('./loadEndpoints-Dh-dSqZX.cjs');
4
- require('./build-CTKUZTHx.cjs');
5
- require('./cli-DLypHuNF.cjs');
6
- require('./openapi-DrPYAlJ_.cjs');
package/dist/index.mjs DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env -S npx tsx
2
- import "./config-DV1Lwdkx.mjs";
3
- import "./loadEndpoints-DKaw6Eqm.mjs";
4
- import "./build-DgeiXkH-.mjs";
5
- import "./cli-BuIVmCrJ.mjs";
6
- import "./openapi-DgLItZw-.mjs";
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env -S npx tsx
2
-
3
- import './cli.ts';
4
-
5
- // Export types for user configuration
6
- export type { GkmConfig, Provider, BuildOptions } from './types.ts';