@geekmidas/cli 0.7.0 → 0.9.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/dist/config.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { GkmConfig } from "./types-C0hwnSjm.cjs";
1
+ import { GkmConfig } from "./types-b-vwGpqc.cjs";
2
2
 
3
3
  //#region src/config.d.ts
4
4
 
package/dist/config.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { GkmConfig } from "./types-B3TXoj7v.mjs";
1
+ import { GkmConfig } from "./types-DXgiA1sF.mjs";
2
2
 
3
3
  //#region src/config.d.ts
4
4
 
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
3
  const require_config = require('./config-CFls09Ey.cjs');
4
- const require_openapi = require('./openapi-tAIbJJU_.cjs');
4
+ const require_openapi = require('./openapi-CHhTPief.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.7.0";
23
+ var version = "0.9.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";
@@ -572,6 +572,16 @@ function normalizeStudioConfig(config) {
572
572
  schema: studioConfig.schema ?? "public"
573
573
  };
574
574
  }
575
+ /**
576
+ * Normalize hooks configuration
577
+ * @internal Exported for testing
578
+ */
579
+ function normalizeHooksConfig(config) {
580
+ if (!config?.server) return void 0;
581
+ const serverPath = config.server.endsWith(".ts") ? config.server : `${config.server}.ts`;
582
+ const resolvedPath = (0, node_path.resolve)(process.cwd(), serverPath);
583
+ return { serverHooksPath: resolvedPath };
584
+ }
575
585
  async function devCommand(options) {
576
586
  const defaultEnv = loadEnvFiles(".env");
577
587
  if (defaultEnv.loaded.length > 0) logger$2.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
@@ -594,31 +604,36 @@ async function devCommand(options) {
594
604
  if (telescope) logger$2.log(`🔭 Telescope enabled at ${telescope.path}`);
595
605
  const studio = normalizeStudioConfig(config.studio);
596
606
  if (studio) logger$2.log(`🗄️ Studio enabled at ${studio.path}`);
607
+ const hooks = normalizeHooksConfig(config.hooks);
608
+ if (hooks) logger$2.log(`🪝 Server hooks enabled from ${config.hooks?.server}`);
597
609
  const openApiConfig = require_openapi.resolveOpenApiConfig(config);
598
610
  const enableOpenApi = openApiConfig.enabled || resolved.enableOpenApi;
599
- if (enableOpenApi) logger$2.log(`📄 OpenAPI output: ${openApiConfig.output}`);
611
+ if (enableOpenApi) logger$2.log(`📄 OpenAPI output: ${require_openapi.OPENAPI_OUTPUT_PATH}`);
600
612
  const buildContext = {
601
613
  envParserPath,
602
614
  envParserImportPattern,
603
615
  loggerPath,
604
616
  loggerImportPattern,
605
617
  telescope,
606
- studio
618
+ studio,
619
+ hooks
607
620
  };
608
621
  await buildServer(config, buildContext, resolved.providers[0], enableOpenApi);
609
622
  if (enableOpenApi) await require_openapi.generateOpenApi(config);
610
623
  const runtime = config.runtime ?? "node";
611
- 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);
612
625
  await devServer.start();
613
626
  const envParserFile = config.envParser.split("#")[0];
614
627
  const loggerFile = config.logger.split("#")[0];
628
+ const hooksFile = config.hooks?.server?.split("#")[0];
615
629
  const watchPatterns = [
616
630
  config.routes,
617
631
  ...config.functions ? [config.functions] : [],
618
632
  ...config.crons ? [config.crons] : [],
619
633
  ...config.subscribers ? [config.subscribers] : [],
620
634
  envParserFile.endsWith(".ts") ? envParserFile : `${envParserFile}.ts`,
621
- loggerFile.endsWith(".ts") ? loggerFile : `${loggerFile}.ts`
635
+ loggerFile.endsWith(".ts") ? loggerFile : `${loggerFile}.ts`,
636
+ ...hooksFile ? [hooksFile.endsWith(".ts") ? hooksFile : `${hooksFile}.ts`] : []
622
637
  ].flat();
623
638
  const normalizedPatterns = watchPatterns.map((p) => p.startsWith("./") ? p.slice(2) : p);
624
639
  logger$2.log(`👀 Watching for changes in: ${normalizedPatterns.join(", ")}`);
@@ -657,11 +672,16 @@ async function devCommand(options) {
657
672
  }
658
673
  }, 300);
659
674
  });
660
- const shutdown = async () => {
675
+ let isShuttingDown = false;
676
+ const shutdown = () => {
677
+ if (isShuttingDown) return;
678
+ isShuttingDown = true;
661
679
  logger$2.log("\n🛑 Shutting down...");
662
- await watcher.close();
663
- await devServer.stop();
664
- process.exit(0);
680
+ Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
681
+ logger$2.error("Error during shutdown:", err);
682
+ }).finally(() => {
683
+ process.exit(0);
684
+ });
665
685
  };
666
686
  process.on("SIGINT", shutdown);
667
687
  process.on("SIGTERM", shutdown);
@@ -693,9 +713,10 @@ var DevServer = class {
693
713
  serverProcess = null;
694
714
  isRunning = false;
695
715
  actualPort;
696
- constructor(provider, requestedPort, enableOpenApi, telescope, studio, runtime = "node") {
716
+ constructor(provider, requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node") {
697
717
  this.provider = provider;
698
718
  this.requestedPort = requestedPort;
719
+ this.portExplicit = portExplicit;
699
720
  this.enableOpenApi = enableOpenApi;
700
721
  this.telescope = telescope;
701
722
  this.studio = studio;
@@ -704,8 +725,14 @@ var DevServer = class {
704
725
  }
705
726
  async start() {
706
727
  if (this.isRunning) await this.stop();
707
- this.actualPort = await findAvailablePort(this.requestedPort);
708
- if (this.actualPort !== this.requestedPort) logger$2.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
728
+ if (this.portExplicit) {
729
+ const available = await isPortAvailable(this.requestedPort);
730
+ 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.`);
731
+ this.actualPort = this.requestedPort;
732
+ } else {
733
+ this.actualPort = await findAvailablePort(this.requestedPort);
734
+ if (this.actualPort !== this.requestedPort) logger$2.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
735
+ }
709
736
  const serverEntryPath = (0, node_path.join)(process.cwd(), ".gkm", this.provider, "server.ts");
710
737
  await this.createServerEntry();
711
738
  logger$2.log(`\n✨ Starting server on port ${this.actualPort}...`);
@@ -739,26 +766,25 @@ var DevServer = class {
739
766
  }
740
767
  }
741
768
  async stop() {
769
+ const port = this.actualPort;
742
770
  if (this.serverProcess && this.isRunning) {
743
771
  const pid = this.serverProcess.pid;
744
772
  if (pid) try {
745
- process.kill(-pid, "SIGTERM");
746
- } catch {}
747
- await new Promise((resolve$1) => {
748
- const timeout = setTimeout(() => {
749
- if (pid) try {
750
- process.kill(-pid, "SIGKILL");
751
- } catch {}
752
- resolve$1();
753
- }, 3e3);
754
- this.serverProcess?.on("exit", () => {
755
- clearTimeout(timeout);
756
- resolve$1();
757
- });
758
- });
773
+ process.kill(-pid, "SIGKILL");
774
+ } catch {
775
+ try {
776
+ process.kill(pid, "SIGKILL");
777
+ } catch {}
778
+ }
759
779
  this.serverProcess = null;
760
780
  this.isRunning = false;
761
781
  }
782
+ this.killProcessesOnPort(port);
783
+ }
784
+ killProcessesOnPort(port) {
785
+ try {
786
+ (0, node_child_process.execSync)(`lsof -ti tcp:${port} | xargs kill -9 2>/dev/null || true`, { stdio: "ignore" });
787
+ } catch {}
762
788
  }
763
789
  async restart() {
764
790
  const portToReuse = this.actualPort;
@@ -899,12 +925,15 @@ async function buildCommand(options) {
899
925
  const { path: loggerPath, importPattern: loggerImportPattern } = require_config.parseModuleConfig(config.logger, "logger");
900
926
  const telescope = normalizeTelescopeConfig(config.telescope);
901
927
  if (telescope) logger.log(`🔭 Telescope enabled at ${telescope.path}`);
928
+ const hooks = normalizeHooksConfig(config.hooks);
929
+ if (hooks) logger.log(`🪝 Server hooks enabled`);
902
930
  const buildContext = {
903
931
  envParserPath,
904
932
  envParserImportPattern,
905
933
  loggerPath,
906
934
  loggerImportPattern,
907
- telescope
935
+ telescope,
936
+ hooks
908
937
  };
909
938
  const endpointGenerator = new require_openapi.EndpointGenerator();
910
939
  const functionGenerator = new FunctionGenerator();
@@ -2283,7 +2312,7 @@ export const telescope = new Telescope({
2283
2312
  /**
2284
2313
  * OpenAPI output path (fixed, not configurable)
2285
2314
  */
2286
- const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
2315
+ const OPENAPI_OUTPUT_PATH$1 = "./.gkm/openapi.ts";
2287
2316
  /**
2288
2317
  * All available templates
2289
2318
  */
@@ -2400,8 +2429,8 @@ function generatePackageJson(options, template) {
2400
2429
  private: true,
2401
2430
  type: "module",
2402
2431
  exports: { "./client": {
2403
- types: OPENAPI_OUTPUT_PATH,
2404
- import: OPENAPI_OUTPUT_PATH
2432
+ types: OPENAPI_OUTPUT_PATH$1,
2433
+ import: OPENAPI_OUTPUT_PATH$1
2405
2434
  } },
2406
2435
  scripts: scripts$1,
2407
2436
  dependencies: sortObject(dependencies$1),
@@ -2679,12 +2708,13 @@ program.command("build").description("Build handlers from endpoints, functions,
2679
2708
  process.exit(1);
2680
2709
  }
2681
2710
  });
2682
- 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) => {
2711
+ 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) => {
2683
2712
  try {
2684
2713
  const globalOptions = program.opts();
2685
2714
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2686
2715
  await devCommand({
2687
2716
  port: options.port ? Number.parseInt(options.port) : 3e3,
2717
+ portExplicit: !!options.port,
2688
2718
  enableOpenApi: options.enableOpenapi ?? true
2689
2719
  });
2690
2720
  } catch (error) {
@@ -2707,11 +2737,11 @@ program.command("api").description("Manage REST API endpoints").action(() => {
2707
2737
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2708
2738
  process.stdout.write("REST API management - coming soon\n");
2709
2739
  });
2710
- 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) => {
2740
+ program.command("openapi").description("Generate OpenAPI specification from endpoints").action(async () => {
2711
2741
  try {
2712
2742
  const globalOptions = program.opts();
2713
2743
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
2714
- await require_openapi.openapiCommand(options);
2744
+ await require_openapi.openapiCommand({});
2715
2745
  } catch (error) {
2716
2746
  console.error("OpenAPI generation failed:", error.message);
2717
2747
  process.exit(1);