@geekmidas/cli 0.8.0 → 0.10.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 (35) hide show
  1. package/dist/{config-Bq72aj8e.mjs → config-BrkUalUh.mjs} +4 -2
  2. package/dist/config-BrkUalUh.mjs.map +1 -0
  3. package/dist/{config-CFls09Ey.cjs → config-C9aXOHBe.cjs} +4 -2
  4. package/dist/config-C9aXOHBe.cjs.map +1 -0
  5. package/dist/config.cjs +1 -1
  6. package/dist/config.d.cts +1 -0
  7. package/dist/config.d.cts.map +1 -0
  8. package/dist/config.d.mts +1 -0
  9. package/dist/config.d.mts.map +1 -0
  10. package/dist/config.mjs +1 -1
  11. package/dist/index.cjs +27 -15
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.mjs +27 -15
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/{openapi-CHhTPief.cjs → openapi-BeHLKcwP.cjs} +13 -13
  16. package/dist/{openapi-CHhTPief.cjs.map → openapi-BeHLKcwP.cjs.map} +1 -1
  17. package/dist/{openapi--vOy9mo4.mjs → openapi-CZLI4QTr.mjs} +13 -13
  18. package/dist/{openapi--vOy9mo4.mjs.map → openapi-CZLI4QTr.mjs.map} +1 -1
  19. package/dist/openapi-react-query.d.cts.map +1 -0
  20. package/dist/openapi-react-query.d.mts.map +1 -0
  21. package/dist/openapi.cjs +2 -2
  22. package/dist/openapi.d.cts.map +1 -0
  23. package/dist/openapi.d.mts.map +1 -0
  24. package/dist/openapi.mjs +2 -2
  25. package/dist/types-DXgiA1sF.d.mts.map +1 -0
  26. package/dist/types-b-vwGpqc.d.cts.map +1 -0
  27. package/package.json +7 -7
  28. package/src/__tests__/test-helpers.ts +3 -2
  29. package/src/config.ts +3 -1
  30. package/src/dev/index.ts +35 -11
  31. package/src/generators/OpenApiTsGenerator.ts +11 -11
  32. package/src/index.ts +11 -18
  33. package/tsconfig.json +9 -0
  34. package/dist/config-Bq72aj8e.mjs.map +0 -1
  35. package/dist/config-CFls09Ey.cjs.map +0 -1
@@ -40,7 +40,9 @@ function defineConfig(config) {
40
40
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
41
41
  */
42
42
  function parseModuleConfig(configString, defaultAlias) {
43
- const [path, exportName] = configString.split("#");
43
+ const parts = configString.split("#");
44
+ const path = parts[0] ?? configString;
45
+ const exportName = parts[1];
44
46
  const importPattern = !exportName ? defaultAlias : exportName === defaultAlias ? `{ ${defaultAlias} }` : `{ ${exportName} as ${defaultAlias} }`;
45
47
  return {
46
48
  path,
@@ -72,4 +74,4 @@ async function loadConfig(cwd = process.cwd()) {
72
74
 
73
75
  //#endregion
74
76
  export { defineConfig, loadConfig, parseModuleConfig };
75
- //# sourceMappingURL=config-Bq72aj8e.mjs.map
77
+ //# sourceMappingURL=config-BrkUalUh.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BrkUalUh.mjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport { join } from 'path';\nimport type { GkmConfig } from './types.ts';\n\nexport type { GkmConfig } from './types.ts';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n return config;\n}\n\nexport interface ParsedModuleConfig {\n path: string;\n importPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n configString: string,\n defaultAlias: string,\n): ParsedModuleConfig {\n const parts = configString.split('#');\n const path = parts[0] ?? configString;\n const exportName = parts[1];\n const importPattern = !exportName\n ? defaultAlias\n : exportName === defaultAlias\n ? `{ ${defaultAlias} }`\n : `{ ${exportName} as ${defaultAlias} }`;\n\n return { path, importPattern };\n}\n\nexport async function loadConfig(\n cwd: string = process.cwd(),\n): Promise<GkmConfig> {\n const files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n let configPath = '';\n\n for (const file of files) {\n const path = join(cwd, file);\n if (existsSync(path)) {\n configPath = path;\n break;\n }\n }\n\n if (!configPath) {\n throw new Error(\n 'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n );\n }\n\n try {\n const config = await import(configPath);\n return config.default;\n } catch (error) {\n throw new Error(\n `Failed to load gkm.config.json: ${(error as Error).message}`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAaA,QAA8B;AACzD,QAAO;AACR;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,kBACdC,cACAC,cACoB;CACpB,MAAM,QAAQ,aAAa,MAAM,IAAI;CACrC,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,aAAa,MAAM;CACzB,MAAM,iBAAiB,aACnB,eACA,eAAe,gBACZ,IAAI,aAAa,OACjB,IAAI,WAAW,MAAM,aAAa;AAEzC,QAAO;EAAE;EAAM;CAAe;AAC/B;AAED,eAAsB,WACpBC,MAAc,QAAQ,KAAK,EACP;CACpB,MAAM,QAAQ;EAAC;EAAmB;EAAiB;CAAgB;CACnE,IAAI,aAAa;AAEjB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,MAAI,WAAW,KAAK,EAAE;AACpB,gBAAa;AACb;EACD;CACF;AAED,MAAK,WACH,OAAM,IAAI,MACR;AAIJ,KAAI;EACF,MAAM,SAAS,MAAM,OAAO;AAC5B,SAAO,OAAO;CACf,SAAQ,OAAO;AACd,QAAM,IAAI,OACP,kCAAmC,MAAgB,QAAQ;CAE/D;AACF"}
@@ -41,7 +41,9 @@ function defineConfig(config) {
41
41
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
42
42
  */
43
43
  function parseModuleConfig(configString, defaultAlias) {
44
- const [path$1, exportName] = configString.split("#");
44
+ const parts = configString.split("#");
45
+ const path$1 = parts[0] ?? configString;
46
+ const exportName = parts[1];
45
47
  const importPattern = !exportName ? defaultAlias : exportName === defaultAlias ? `{ ${defaultAlias} }` : `{ ${exportName} as ${defaultAlias} }`;
46
48
  return {
47
49
  path: path$1,
@@ -90,4 +92,4 @@ Object.defineProperty(exports, 'parseModuleConfig', {
90
92
  return parseModuleConfig;
91
93
  }
92
94
  });
93
- //# sourceMappingURL=config-CFls09Ey.cjs.map
95
+ //# sourceMappingURL=config-C9aXOHBe.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-C9aXOHBe.cjs","names":["config: GkmConfig","configString: string","defaultAlias: string","path","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport { join } from 'path';\nimport type { GkmConfig } from './types.ts';\n\nexport type { GkmConfig } from './types.ts';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n return config;\n}\n\nexport interface ParsedModuleConfig {\n path: string;\n importPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n configString: string,\n defaultAlias: string,\n): ParsedModuleConfig {\n const parts = configString.split('#');\n const path = parts[0] ?? configString;\n const exportName = parts[1];\n const importPattern = !exportName\n ? defaultAlias\n : exportName === defaultAlias\n ? `{ ${defaultAlias} }`\n : `{ ${exportName} as ${defaultAlias} }`;\n\n return { path, importPattern };\n}\n\nexport async function loadConfig(\n cwd: string = process.cwd(),\n): Promise<GkmConfig> {\n const files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n let configPath = '';\n\n for (const file of files) {\n const path = join(cwd, file);\n if (existsSync(path)) {\n configPath = path;\n break;\n }\n }\n\n if (!configPath) {\n throw new Error(\n 'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n );\n }\n\n try {\n const config = await import(configPath);\n return config.default;\n } catch (error) {\n throw new Error(\n `Failed to load gkm.config.json: ${(error as Error).message}`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAaA,QAA8B;AACzD,QAAO;AACR;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,kBACdC,cACAC,cACoB;CACpB,MAAM,QAAQ,aAAa,MAAM,IAAI;CACrC,MAAMC,SAAO,MAAM,MAAM;CACzB,MAAM,aAAa,MAAM;CACzB,MAAM,iBAAiB,aACnB,eACA,eAAe,gBACZ,IAAI,aAAa,OACjB,IAAI,WAAW,MAAM,aAAa;AAEzC,QAAO;EAAE;EAAM;CAAe;AAC/B;AAED,eAAsB,WACpBC,MAAc,QAAQ,KAAK,EACP;CACpB,MAAM,QAAQ;EAAC;EAAmB;EAAiB;CAAgB;CACnE,IAAI,aAAa;AAEjB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAMD,SAAO,eAAK,KAAK,KAAK;AAC5B,MAAI,mBAAWA,OAAK,EAAE;AACpB,gBAAaA;AACb;EACD;CACF;AAED,MAAK,WACH,OAAM,IAAI,MACR;AAIJ,KAAI;EACF,MAAM,SAAS,MAAM,OAAO;AAC5B,SAAO,OAAO;CACf,SAAQ,OAAO;AACd,QAAM,IAAI,OACP,kCAAmC,MAAgB,QAAQ;CAE/D;AACF"}
package/dist/config.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_config = require('./config-CFls09Ey.cjs');
1
+ const require_config = require('./config-C9aXOHBe.cjs');
2
2
 
3
3
  exports.defineConfig = require_config.defineConfig;
4
4
  exports.loadConfig = require_config.loadConfig;
package/dist/config.d.cts CHANGED
@@ -43,6 +43,7 @@ interface ParsedModuleConfig {
43
43
  */
44
44
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
45
45
  declare function loadConfig(cwd?: string): Promise<GkmConfig>;
46
+ //# sourceMappingURL=config.d.ts.map
46
47
  //#endregion
47
48
  export { GkmConfig, ParsedModuleConfig, defineConfig, loadConfig, parseModuleConfig };
48
49
  //# sourceMappingURL=config.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;AAsBA;;;;AAA0D;AAI1D;AAsBA;AAgBA;;;;AAEU;;;;;iBA5CM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;iBAamB,UAAA,gBAEnB,QAAQ"}
package/dist/config.d.mts CHANGED
@@ -43,6 +43,7 @@ interface ParsedModuleConfig {
43
43
  */
44
44
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
45
45
  declare function loadConfig(cwd?: string): Promise<GkmConfig>;
46
+ //# sourceMappingURL=config.d.ts.map
46
47
  //#endregion
47
48
  export { GkmConfig, ParsedModuleConfig, defineConfig, loadConfig, parseModuleConfig };
48
49
  //# sourceMappingURL=config.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;AAsBA;;;;AAA0D;AAI1D;AAsBA;AAgBA;;;;AAEU;;;;;iBA5CM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;iBAamB,UAAA,gBAEnB,QAAQ"}
package/dist/config.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { defineConfig, loadConfig, parseModuleConfig } from "./config-Bq72aj8e.mjs";
1
+ import { defineConfig, loadConfig, parseModuleConfig } from "./config-BrkUalUh.mjs";
2
2
 
3
3
  export { defineConfig, loadConfig, parseModuleConfig };
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  const require_chunk = require('./chunk-CUT6urMc.cjs');
3
- const require_config = require('./config-CFls09Ey.cjs');
4
- const require_openapi = require('./openapi-CHhTPief.cjs');
3
+ const require_config = require('./config-C9aXOHBe.cjs');
4
+ const require_openapi = require('./openapi-BeHLKcwP.cjs');
5
5
  const require_openapi_react_query = require('./openapi-react-query-o5iMi8tz.cjs');
6
6
  const path = require_chunk.__toESM(require("path"));
7
7
  const commander = require_chunk.__toESM(require("commander"));
@@ -20,7 +20,7 @@ const prompts = require_chunk.__toESM(require("prompts"));
20
20
 
21
21
  //#region package.json
22
22
  var name = "@geekmidas/cli";
23
- var version = "0.8.0";
23
+ var version = "0.10.0";
24
24
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
25
25
  var private$1 = false;
26
26
  var type = "module";
@@ -621,11 +621,12 @@ async function devCommand(options) {
621
621
  await buildServer(config, buildContext, resolved.providers[0], enableOpenApi);
622
622
  if (enableOpenApi) await require_openapi.generateOpenApi(config);
623
623
  const runtime = config.runtime ?? "node";
624
- const devServer = new DevServer(resolved.providers[0], options.port || 3e3, enableOpenApi, telescope, studio, runtime);
624
+ const devServer = new DevServer(resolved.providers[0], options.port || 3e3, options.portExplicit ?? false, enableOpenApi, telescope, studio, runtime);
625
625
  await devServer.start();
626
- const envParserFile = config.envParser.split("#")[0];
627
- const loggerFile = config.logger.split("#")[0];
628
- const hooksFile = config.hooks?.server?.split("#")[0];
626
+ const envParserFile = config.envParser.split("#")[0] ?? config.envParser;
627
+ const loggerFile = config.logger.split("#")[0] ?? config.logger;
628
+ const hooksFileParts = config.hooks?.server?.split("#");
629
+ const hooksFile = hooksFileParts?.[0];
629
630
  const watchPatterns = [
630
631
  config.routes,
631
632
  ...config.functions ? [config.functions] : [],
@@ -634,7 +635,7 @@ async function devCommand(options) {
634
635
  envParserFile.endsWith(".ts") ? envParserFile : `${envParserFile}.ts`,
635
636
  loggerFile.endsWith(".ts") ? loggerFile : `${loggerFile}.ts`,
636
637
  ...hooksFile ? [hooksFile.endsWith(".ts") ? hooksFile : `${hooksFile}.ts`] : []
637
- ].flat();
638
+ ].flat().filter((p) => typeof p === "string");
638
639
  const normalizedPatterns = watchPatterns.map((p) => p.startsWith("./") ? p.slice(2) : p);
639
640
  logger$2.log(`👀 Watching for changes in: ${normalizedPatterns.join(", ")}`);
640
641
  const resolvedFiles = await (0, fast_glob.default)(normalizedPatterns, {
@@ -642,7 +643,10 @@ async function devCommand(options) {
642
643
  absolute: false,
643
644
  onlyFiles: true
644
645
  });
645
- const dirsToWatch = [...new Set(resolvedFiles.map((f) => f.split("/").slice(0, -1).join("/")))];
646
+ const dirsToWatch = [...new Set(resolvedFiles.map((f) => {
647
+ const parts = f.split("/");
648
+ return parts.slice(0, -1).join("/");
649
+ }))];
646
650
  logger$2.log(`📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`);
647
651
  const watcher = chokidar.default.watch([...resolvedFiles, ...dirsToWatch], {
648
652
  ignored: /(^|[\/\\])\../,
@@ -713,9 +717,10 @@ var DevServer = class {
713
717
  serverProcess = null;
714
718
  isRunning = false;
715
719
  actualPort;
716
- constructor(provider, requestedPort, enableOpenApi, telescope, studio, runtime = "node") {
720
+ constructor(provider, requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node") {
717
721
  this.provider = provider;
718
722
  this.requestedPort = requestedPort;
723
+ this.portExplicit = portExplicit;
719
724
  this.enableOpenApi = enableOpenApi;
720
725
  this.telescope = telescope;
721
726
  this.studio = studio;
@@ -724,8 +729,14 @@ var DevServer = class {
724
729
  }
725
730
  async start() {
726
731
  if (this.isRunning) await this.stop();
727
- this.actualPort = await findAvailablePort(this.requestedPort);
728
- if (this.actualPort !== this.requestedPort) logger$2.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
732
+ if (this.portExplicit) {
733
+ const available = await isPortAvailable(this.requestedPort);
734
+ if (!available) throw new Error(`Port ${this.requestedPort} is already in use. Either stop the process using that port or omit -p/--port to auto-select an available port.`);
735
+ this.actualPort = this.requestedPort;
736
+ } else {
737
+ this.actualPort = await findAvailablePort(this.requestedPort);
738
+ if (this.actualPort !== this.requestedPort) logger$2.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
739
+ }
729
740
  const serverEntryPath = (0, node_path.join)(process.cwd(), ".gkm", this.provider, "server.ts");
730
741
  await this.createServerEntry();
731
742
  logger$2.log(`\n✨ Starting server on port ${this.actualPort}...`);
@@ -2701,12 +2712,13 @@ program.command("build").description("Build handlers from endpoints, functions,
2701
2712
  process.exit(1);
2702
2713
  }
2703
2714
  });
2704
- program.command("dev").description("Start development server with automatic reload").option("--port <port>", "Port to run the development server on", "3000").option("--enable-openapi", "Enable OpenAPI documentation for development server", true).action(async (options) => {
2715
+ program.command("dev").description("Start development server with automatic reload").option("-p, --port <port>", "Port to run the development server on").option("--enable-openapi", "Enable OpenAPI documentation for development server", true).action(async (options) => {
2705
2716
  try {
2706
2717
  const globalOptions = program.opts();
2707
2718
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2708
2719
  await devCommand({
2709
2720
  port: options.port ? Number.parseInt(options.port) : 3e3,
2721
+ portExplicit: !!options.port,
2710
2722
  enableOpenApi: options.enableOpenapi ?? true
2711
2723
  });
2712
2724
  } catch (error) {
@@ -2729,11 +2741,11 @@ program.command("api").description("Manage REST API endpoints").action(() => {
2729
2741
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2730
2742
  process.stdout.write("REST API management - coming soon\n");
2731
2743
  });
2732
- program.command("openapi").description("Generate OpenAPI specification from endpoints (TypeScript by default)").option("--output <path>", "Output file path for the OpenAPI spec", "openapi.ts").option("--json", "Generate JSON instead of TypeScript (legacy)", false).action(async (options) => {
2744
+ program.command("openapi").description("Generate OpenAPI specification from endpoints").action(async () => {
2733
2745
  try {
2734
2746
  const globalOptions = program.opts();
2735
2747
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2736
- await require_openapi.openapiCommand(options);
2748
+ await require_openapi.openapiCommand({});
2737
2749
  } catch (error) {
2738
2750
  console.error("OpenAPI generation failed:", error.message);
2739
2751
  process.exit(1);