@devbro/pashmak 0.1.47 → 0.1.49

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 (42) hide show
  1. package/dist/DatabaseServiceProvider.d.mts +4 -1
  2. package/dist/DatabaseServiceProvider.mjs +5 -2
  3. package/dist/DatabaseServiceProvider.mjs.map +1 -1
  4. package/dist/app/console/StartCommand.d.mts +1 -0
  5. package/dist/app/console/StartCommand.mjs +5 -2
  6. package/dist/app/console/StartCommand.mjs.map +1 -1
  7. package/dist/app/console/generate/GenerateApiDocsCommand.d.mts +34 -2
  8. package/dist/app/console/generate/GenerateApiDocsCommand.mjs +183 -100
  9. package/dist/app/console/generate/GenerateApiDocsCommand.mjs.map +1 -1
  10. package/dist/app/console/project/base_project/src/config/storages.ts.tpl +2 -2
  11. package/dist/bin/DatabaseServiceProvider.cjs +8 -2
  12. package/dist/bin/app/console/DefaultCommand.cjs +64 -32
  13. package/dist/bin/app/console/KeyGenerateCommand.cjs +64 -32
  14. package/dist/bin/app/console/StartCommand.cjs +69 -34
  15. package/dist/bin/app/console/generate/GenerateApiDocsCommand.cjs +248 -133
  16. package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +64 -32
  17. package/dist/bin/app/console/generate/index.cjs +248 -133
  18. package/dist/bin/app/console/index.cjs +253 -135
  19. package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +64 -32
  20. package/dist/bin/app/console/migrate/MigrateCommand.cjs +64 -32
  21. package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +64 -32
  22. package/dist/bin/app/console/migrate/index.cjs +64 -32
  23. package/dist/bin/app/console/queue/GenerateQueueMigrateCommand.cjs +64 -32
  24. package/dist/bin/cache.cjs +64 -32
  25. package/dist/bin/facades.cjs +64 -32
  26. package/dist/bin/factories.cjs +64 -32
  27. package/dist/bin/http.cjs +739 -0
  28. package/dist/bin/index.cjs +264 -141
  29. package/dist/bin/middlewares.cjs +66 -34
  30. package/dist/bin/queue.cjs +64 -32
  31. package/dist/bin/router.cjs +4 -8
  32. package/dist/config.d.mts +0 -1
  33. package/dist/facades.mjs +2 -13
  34. package/dist/facades.mjs.map +1 -1
  35. package/dist/factories.mjs +45 -2
  36. package/dist/factories.mjs.map +1 -1
  37. package/dist/http.d.mts +4 -0
  38. package/dist/http.mjs +20 -0
  39. package/dist/http.mjs.map +1 -1
  40. package/dist/queue.d.mts +1 -1
  41. package/dist/queue.mjs.map +1 -1
  42. package/package.json +1 -1
@@ -89,13 +89,14 @@ var init_MiddlewareFactory = __esm({
89
89
  });
90
90
 
91
91
  // ../neko-router/dist/CompiledRoute.mjs
92
- var import_stream, CompiledRoute;
92
+ var import_stream, import_neko_helper, CompiledRoute;
93
93
  var init_CompiledRoute = __esm({
94
94
  "../neko-router/dist/CompiledRoute.mjs"() {
95
95
  "use strict";
96
96
  import_stream = require("stream");
97
97
  init_Middleware();
98
98
  init_MiddlewareFactory();
99
+ import_neko_helper = require("@devbro/neko-helper");
99
100
  CompiledRoute = class {
100
101
  static {
101
102
  __name(this, "CompiledRoute");
@@ -116,7 +117,7 @@ var init_CompiledRoute = __esm({
116
117
  for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {
117
118
  if (middleware instanceof Middleware) {
118
119
  this.middlewares.push(middleware);
119
- } else if (this.isClass(middleware)) {
120
+ } else if ((0, import_neko_helper.isClass)(middleware)) {
120
121
  this.middlewares.push(middleware.getInstance({}));
121
122
  } else if (typeof middleware === "function") {
122
123
  this.middlewares.push(MiddlewareFactory.create(middleware));
@@ -125,13 +126,8 @@ var init_CompiledRoute = __esm({
125
126
  }
126
127
  }
127
128
  }
128
- isClass(func) {
129
- return typeof func === "function" && /^class\s/.test(Function.prototype.toString.call(func));
130
- }
131
129
  async run() {
132
- let rc = await this.runMiddlewares(this.middlewares, this.request, this.response);
133
- this.response.end();
134
- return rc;
130
+ return await this.runMiddlewares(this.middlewares, this.request, this.response);
135
131
  }
136
132
  prepareOutputJsonFormat(obj) {
137
133
  function traverse(value) {
@@ -278,7 +274,7 @@ var init_Route = __esm({
278
274
  i = start;
279
275
  } else if (char === "*") {
280
276
  let start = i + 1;
281
- while (start < path10.length && /[a-zA-Z0-9_\.]/.test(path10[start])) {
277
+ while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
282
278
  start++;
283
279
  }
284
280
  tokens.push({ type: "WILDCARD", value: path10.slice(i + 1, start) });
@@ -557,10 +553,29 @@ var init_router = __esm({
557
553
 
558
554
  // src/http.mts
559
555
  var http_exports = {};
556
+ __export(http_exports, {
557
+ handleHttpErrors: () => handleHttpErrors
558
+ });
559
+ async function handleHttpErrors(err, req, res) {
560
+ if (err instanceof import_neko_http.HttpError) {
561
+ res.writeHead(err.statusCode, { "Content-Type": "application/json" });
562
+ res.write(JSON.stringify({ message: err.message, error: err.code }));
563
+ logger().warn({ msg: "HttpError: " + err.message, err });
564
+ return;
565
+ } else {
566
+ logger().error({ msg: "Error: " + err.message, err });
567
+ }
568
+ res.writeHead(500, { "Content-Type": "application/json" });
569
+ res.write(JSON.stringify({ error: "Internal Server Error" }));
570
+ }
571
+ var import_neko_http;
560
572
  var init_http = __esm({
561
573
  "src/http.mts"() {
562
574
  "use strict";
575
+ import_neko_http = require("@devbro/neko-http");
576
+ init_facades();
563
577
  __reExport(http_exports, require("@devbro/neko-http"));
578
+ __name(handleHttpErrors, "handleHttpErrors");
564
579
  }
565
580
  });
566
581
 
@@ -569,13 +584,13 @@ var queue_exports = {};
569
584
  __export(queue_exports, {
570
585
  DatabaseTransport: () => DatabaseTransport
571
586
  });
572
- var import_neko_helper, import_neko_context2, DatabaseTransport;
587
+ var import_neko_helper2, import_neko_context2, DatabaseTransport;
573
588
  var init_queue = __esm({
574
589
  "src/queue.mts"() {
575
590
  "use strict";
576
591
  __reExport(queue_exports, require("@devbro/neko-queue"));
577
592
  init_facades();
578
- import_neko_helper = require("@devbro/neko-helper");
593
+ import_neko_helper2 = require("@devbro/neko-helper");
579
594
  import_neko_context2 = require("@devbro/neko-context");
580
595
  DatabaseTransport = class {
581
596
  static {
@@ -636,7 +651,7 @@ var init_queue = __esm({
636
651
  }, "processMessage");
637
652
  constructor(config11 = {}) {
638
653
  this.config = { ...this.config, ...config11 };
639
- this.repeater = (0, import_neko_helper.createRepeater)(
654
+ this.repeater = (0, import_neko_helper2.createRepeater)(
640
655
  this.processMessage,
641
656
  this.config.listen_interval * 1e3
642
657
  );
@@ -713,6 +728,24 @@ var init_factories = __esm({
713
728
  import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
714
729
  return new import_neko_queue.MemoryTransport(opt);
715
730
  });
731
+ import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
732
+ return new import_neko_queue.AwsSqsTransport(opt);
733
+ });
734
+ import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
735
+ return new import_neko_queue.AmqpTransport(opt);
736
+ });
737
+ import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
738
+ return new import_neko_queue.RedisTransport(opt);
739
+ });
740
+ import_neko_queue.QueueTransportFactory.register("async", (opt) => {
741
+ return new import_neko_queue.AsyncTransport();
742
+ });
743
+ import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
744
+ return new import_neko_queue.AzureServiceBusTransport(opt);
745
+ });
746
+ import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
747
+ return new import_neko_queue.GooglePubSubTransport(opt);
748
+ });
716
749
  CacheProviderFactory = class _CacheProviderFactory {
717
750
  static {
718
751
  __name(this, "CacheProviderFactory");
@@ -743,17 +776,29 @@ var init_factories = __esm({
743
776
  import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
744
777
  return new import_neko_storage.AWSS3StorageProvider(opt);
745
778
  });
779
+ import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
780
+ return new import_neko_storage.GCPStorageProvider(opt);
781
+ });
782
+ import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
783
+ return new import_neko_storage.AzureBlobStorageProvider(opt);
784
+ });
785
+ import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
786
+ return new import_neko_storage.FTPStorageProvider(opt);
787
+ });
788
+ import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
789
+ return new import_neko_storage.SFTPStorageProvider(opt);
790
+ });
746
791
  }
747
792
  });
748
793
 
749
794
  // src/facades.mts
750
- var import_neko_scheduler, import_neko_helper2, import_neko_context3, import_neko_storage2, import_neko_mailer2, import_neko_config, import_clipanion, import_neko_logger, import_neko_cache2, import_neko_queue2, router, scheduler, db, storage, cli, httpServer, logger, mailer, queue, cache;
795
+ var import_neko_scheduler, import_neko_helper3, import_neko_context3, import_neko_storage2, import_neko_mailer2, import_neko_config, import_clipanion, import_neko_logger, import_neko_cache2, import_neko_queue2, router, scheduler, db, storage, cli, httpServer, logger, mailer, queue, cache;
751
796
  var init_facades = __esm({
752
797
  "src/facades.mts"() {
753
798
  "use strict";
754
799
  init_router();
755
800
  import_neko_scheduler = require("@devbro/neko-scheduler");
756
- import_neko_helper2 = require("@devbro/neko-helper");
801
+ import_neko_helper3 = require("@devbro/neko-helper");
757
802
  import_neko_context3 = require("@devbro/neko-context");
758
803
  import_neko_storage2 = require("@devbro/neko-storage");
759
804
  import_neko_mailer2 = require("@devbro/neko-mailer");
@@ -764,8 +809,8 @@ var init_facades = __esm({
764
809
  init_factories();
765
810
  import_neko_cache2 = require("@devbro/neko-cache");
766
811
  import_neko_queue2 = require("@devbro/neko-queue");
767
- router = (0, import_neko_helper2.createSingleton)(() => new Router());
768
- scheduler = (0, import_neko_helper2.createSingleton)(() => {
812
+ router = (0, import_neko_helper3.createSingleton)(() => new Router());
813
+ scheduler = (0, import_neko_helper3.createSingleton)(() => {
769
814
  const rc = new import_neko_scheduler.Scheduler();
770
815
  rc.setErrorHandler((err, job) => {
771
816
  logger().error({
@@ -777,7 +822,7 @@ var init_facades = __esm({
777
822
  return rc;
778
823
  });
779
824
  db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
780
- storage = (0, import_neko_helper2.createSingleton)((label = "default") => {
825
+ storage = (0, import_neko_helper3.createSingleton)((label = "default") => {
781
826
  let storage_config = import_neko_config.config.get(["storages", label].join("."));
782
827
  const provider = import_neko_storage2.StorageProviderFactory.create(
783
828
  storage_config.provider,
@@ -785,7 +830,7 @@ var init_facades = __esm({
785
830
  );
786
831
  return new import_neko_storage2.Storage(provider);
787
832
  });
788
- cli = (0, import_neko_helper2.createSingleton)(() => {
833
+ cli = (0, import_neko_helper3.createSingleton)(() => {
789
834
  const [node, app, ...args] = process.argv;
790
835
  return new import_clipanion.Cli({
791
836
  binaryLabel: `My Application`,
@@ -793,24 +838,13 @@ var init_facades = __esm({
793
838
  binaryVersion: `1.0.0`
794
839
  });
795
840
  });
796
- httpServer = (0, import_neko_helper2.createSingleton)(() => {
841
+ httpServer = (0, import_neko_helper3.createSingleton)(() => {
797
842
  const server = new http_exports.HttpServer();
798
- server.setErrorHandler(async (err, req, res) => {
799
- if (err instanceof http_exports.HttpError) {
800
- res.writeHead(err.statusCode, { "Content-Type": "application/json" });
801
- res.end(JSON.stringify({ message: err.message, error: err.code }));
802
- logger().warn({ msg: "HttpError: " + err.message, err });
803
- return;
804
- } else {
805
- logger().error({ msg: "Error: " + err.message, err });
806
- }
807
- res.writeHead(500, { "Content-Type": "" });
808
- res.end(JSON.stringify({ error: "Internal Server Error" }));
809
- });
843
+ server.setErrorHandler(handleHttpErrors);
810
844
  server.setRouter(router());
811
845
  return server;
812
846
  });
813
- logger = (0, import_neko_helper2.createSingleton)((label) => {
847
+ logger = (0, import_neko_helper3.createSingleton)((label) => {
814
848
  const logger_config = import_neko_config.config.get(["loggers", label].join("."));
815
849
  const rc = new import_neko_logger.Logger(logger_config);
816
850
  rc.setExtrasFunction((message) => {
@@ -819,7 +853,7 @@ var init_facades = __esm({
819
853
  });
820
854
  return rc;
821
855
  });
822
- mailer = (0, import_neko_helper2.createSingleton)((label) => {
856
+ mailer = (0, import_neko_helper3.createSingleton)((label) => {
823
857
  const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
824
858
  const provider = import_neko_mailer2.MailerProviderFactory.create(
825
859
  mailer_config.provider,
@@ -828,7 +862,7 @@ var init_facades = __esm({
828
862
  const rc = new import_neko_mailer2.Mailer(provider);
829
863
  return rc;
830
864
  });
831
- queue = (0, import_neko_helper2.createSingleton)((label) => {
865
+ queue = (0, import_neko_helper3.createSingleton)((label) => {
832
866
  const queue_config = import_neko_config.config.get(["queues", label].join("."));
833
867
  if (!queue_config) {
834
868
  throw new Error(`Queue configuration for '${label}' not found`);
@@ -839,7 +873,7 @@ var init_facades = __esm({
839
873
  );
840
874
  return new import_neko_queue2.QueueConnection(provider);
841
875
  });
842
- cache = (0, import_neko_helper2.createSingleton)((label) => {
876
+ cache = (0, import_neko_helper3.createSingleton)((label) => {
843
877
  const cache_config = import_neko_config.config.get(["caches", label].join("."));
844
878
  if (!cache_config) {
845
879
  throw new Error(`Cache configuration for '${label}' not found`);
@@ -2254,12 +2288,15 @@ var init_StartCommand = __esm({
2254
2288
  __name(this, "StartCommand");
2255
2289
  }
2256
2290
  scheduler = import_clipanion5.Option.Boolean(`--scheduler`, false);
2291
+ cron = import_clipanion5.Option.Boolean(`--cron`, false);
2257
2292
  http = import_clipanion5.Option.Boolean(`--http`, false);
2258
2293
  queue = import_clipanion5.Option.Boolean(`--queue`, false);
2259
2294
  all = import_clipanion5.Option.Boolean("--all", false);
2260
2295
  static paths = [[`start`]];
2261
2296
  async execute() {
2262
- if ([this.all, this.http, this.scheduler, this.queue].filter((x) => x).length == 0) {
2297
+ if ([this.all, this.http, this.scheduler || this.cron, this.queue].filter(
2298
+ (x) => x
2299
+ ).length == 0) {
2263
2300
  this.context.stdout.write(
2264
2301
  `No service was selected. please check -h for details
2265
2302
  `
@@ -2269,7 +2306,7 @@ var init_StartCommand = __esm({
2269
2306
  logger().info(`Starting Server
2270
2307
  `);
2271
2308
  import_neko_sql.PostgresqlConnection.defaults.idleTimeoutMillis = 1e4;
2272
- if (this.scheduler || this.all) {
2309
+ if (this.scheduler || this.cron || this.all) {
2273
2310
  logger().info(`starting scheduler
2274
2311
  `);
2275
2312
  scheduler().start();
@@ -2490,7 +2527,7 @@ var init_config = __esm({
2490
2527
  });
2491
2528
 
2492
2529
  // src/app/console/generate/GenerateApiDocsCommand.mts
2493
- var import_clipanion9, import_path7, fs6, import_neko_helper3, GenerateApiDocsCommand;
2530
+ var import_clipanion9, import_path7, fs6, import_neko_helper4, GenerateApiDocsCommand;
2494
2531
  var init_GenerateApiDocsCommand = __esm({
2495
2532
  "src/app/console/generate/GenerateApiDocsCommand.mts"() {
2496
2533
  "use strict";
@@ -2499,144 +2536,155 @@ var init_GenerateApiDocsCommand = __esm({
2499
2536
  import_path7 = __toESM(require("path"), 1);
2500
2537
  fs6 = __toESM(require("fs/promises"), 1);
2501
2538
  init_config();
2502
- import_neko_helper3 = require("@devbro/neko-helper");
2539
+ import_neko_helper4 = require("@devbro/neko-helper");
2503
2540
  GenerateApiDocsCommand = class extends import_clipanion9.Command {
2504
2541
  static {
2505
2542
  __name(this, "GenerateApiDocsCommand");
2506
2543
  }
2507
- static paths = [
2508
- [`make`, `apidocs`],
2509
- [`generate`, `apidocs`]
2510
- ];
2544
+ static paths = [[`generate`, `apidocsv2`]];
2511
2545
  static usage = import_clipanion9.Command.Usage({
2512
2546
  category: `Generate`,
2513
2547
  description: `Generate OpenAPI documentation from routes`,
2514
2548
  details: `
2515
- This command generates OpenAPI 3.0 specification documentation by analyzing
2549
+ This command utility generates OpenAPI 3.0 specification documentation by analyzing
2516
2550
  your application's routes and merging with example files.
2517
2551
 
2518
- The generated documentation includes:
2519
- - All registered routes with their HTTP methods
2520
- - Path parameters extracted from route definitions
2521
- - Request body schemas for POST, PUT, and PATCH methods
2522
- - Response schemas
2523
-
2524
- The command will merge files specified in config.api_docs.merge_files
2525
- and output the final documentation to config.api_docs.output.
2552
+ Subcommands:
2553
+ - generate-from-routes: Generate OpenAPI spec from registered routes
2554
+ - generate-base: Generate base OpenAPI specification structure
2555
+ - merge-files: Merge multiple OpenAPI files into final documentation
2526
2556
 
2557
+
2527
2558
  This command depends on config data. make sure your default config contains the following:
2528
- api_docs: {
2529
- merge_files: [
2530
- path.join(__dirname, '../..', 'private', 'openapi_examples.json'),
2531
- path.join(__dirname, '../..', 'private', 'openapi_base.json'),
2532
- path.join(__dirname, '../..', 'private', 'openapi_user_changes.json'),
2533
- ],
2534
- output: path.join(__dirname, '../..', 'private', 'openapi.json'),
2535
- }
2559
+
2560
+ \`\`\`
2561
+ api_docs: {
2562
+
2563
+ merge_files: [
2564
+
2565
+ path.join(__dirname, '../..', 'private', 'openapi_base.json'),
2566
+
2567
+ path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),
2568
+
2569
+ path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),
2570
+
2571
+ path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),
2572
+
2573
+ ],
2574
+
2575
+ output: path.join(__dirname, '../..', 'public', 'openapi.json'),
2576
+
2577
+ }
2578
+
2579
+ \`\`\`
2536
2580
  `,
2537
- examples: [[`Generate API documentation`, `$0 generate apidocs`]]
2581
+ examples: [
2582
+ [
2583
+ `Generate from routes`,
2584
+ `$0 generate apidocsv2 generate-from-routes --output path/to/output.json`
2585
+ ],
2586
+ [
2587
+ `Generate base spec`,
2588
+ `$0 generate apidocsv2 generate-base --output path/to/output.json`
2589
+ ],
2590
+ [`Merge files`, `$0 generate apidocsv2 merge-files`],
2591
+ [`Show help`, `$0 generate apidocsv2 --help`]
2592
+ ]
2593
+ });
2594
+ subcommand = import_clipanion9.Option.String({ required: false });
2595
+ output = import_clipanion9.Option.String(`--output,-o`, {
2596
+ description: `Output file path for generated documentation`
2538
2597
  });
2539
- help = import_clipanion9.Option.Boolean(`--help,-h`, false, {
2540
- description: `Show help message for this command`
2598
+ config = import_clipanion9.Option.String(`--config,-c`, {
2599
+ description: `Path in config to get details from (default: api_docs)`,
2600
+ required: false
2541
2601
  });
2542
2602
  async execute() {
2543
- if (this.help) {
2603
+ if (!this.subcommand) {
2544
2604
  this.context.stdout.write(
2545
2605
  this.constructor.usage?.toString() || "No help available\n"
2546
2606
  );
2547
2607
  return 0;
2548
2608
  }
2549
- const rootDir = process.cwd();
2550
- this.context.stdout.write(`Generating OpenAPI documentation...
2609
+ switch (this.subcommand) {
2610
+ case "generate-from-routes":
2611
+ return await this.executeGenerateFromRoutes();
2612
+ case "generate-base":
2613
+ return await this.executeGenerateBase();
2614
+ case "merge-files":
2615
+ return await this.executeMergeFiles();
2616
+ default:
2617
+ this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
2551
2618
  `);
2552
- const routes = router().routes;
2553
- const openApiSpec = {
2554
- openapi: "3.0.0",
2555
- info: {
2556
- title: "API Documentation",
2557
- version: "1.0.0",
2558
- description: "Auto-generated API documentation"
2559
- },
2560
- servers: [
2561
- {
2562
- url: "/",
2563
- description: "Local server"
2564
- }
2565
- ],
2566
- paths: {}
2567
- };
2568
- for (const route of routes) {
2569
- const routePath = route.path;
2570
- const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
2571
- if (!openApiSpec.paths[openApiPath]) {
2572
- openApiSpec.paths[openApiPath] = {};
2573
- }
2574
- for (const method of route.methods) {
2575
- const lowerMethod = method.toLowerCase();
2576
- if (lowerMethod === "head") {
2577
- continue;
2578
- }
2579
- openApiSpec.paths[openApiPath][lowerMethod] = {
2580
- summary: `${method} ${routePath}`,
2581
- description: `Endpoint for ${method} ${routePath}`,
2582
- parameters: this.extractParameters(routePath),
2583
- responses: {
2584
- "200": {
2585
- description: "Successful response",
2586
- content: {
2587
- "application/json": {
2588
- schema: {
2589
- type: "object"
2590
- }
2591
- }
2592
- }
2593
- },
2594
- "500": {
2595
- description: "Internal server error"
2596
- }
2597
- }
2598
- };
2599
- if (["post", "put", "patch"].includes(lowerMethod)) {
2600
- openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
2601
- required: true,
2602
- content: {
2603
- "application/json": {
2604
- schema: {
2605
- type: "object"
2606
- }
2607
- }
2608
- }
2609
- };
2610
- }
2611
- }
2619
+ this.context.stdout.write(
2620
+ this.constructor.usage?.toString() || "No help available\n"
2621
+ );
2622
+ return 1;
2612
2623
  }
2613
- await fs6.mkdir(config_exports.config.get("private_path"), { recursive: true });
2614
- const outputPath = import_path7.default.join(config_exports.config.get("private_path"), "openapi.json");
2624
+ }
2625
+ async executeGenerateFromRoutes() {
2626
+ this.context.stdout.write(
2627
+ `Generating OpenAPI documentation from routes...
2628
+ `
2629
+ );
2630
+ const openApiSpec = this.generateFromRoutes();
2631
+ const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
2632
+ await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
2615
2633
  await fs6.writeFile(
2616
2634
  outputPath,
2617
2635
  JSON.stringify(openApiSpec, null, 2),
2618
2636
  "utf-8"
2619
2637
  );
2620
2638
  this.context.stdout.write(
2621
- `OpenAPI documentation generated at: ${outputPath}
2639
+ `OpenAPI routes documentation generated at: ${outputPath}
2622
2640
  `
2623
2641
  );
2624
- this.context.stdout.write(`Total routes documented: ${routes.length}
2642
+ this.context.stdout.write(
2643
+ `Total routes documented: ${Object.keys(openApiSpec.paths).length}
2644
+ `
2645
+ );
2646
+ return 0;
2647
+ }
2648
+ async executeGenerateBase() {
2649
+ this.context.stdout.write(`Generating base OpenAPI specification...
2625
2650
  `);
2626
- let files_to_merge = config_exports.config.get("api_docs.merge_files");
2651
+ const baseSpec = this.getBaseOpenApiSpec();
2652
+ const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_base.json");
2653
+ await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
2654
+ await fs6.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
2655
+ this.context.stdout.write(
2656
+ `Base OpenAPI specification generated at: ${outputPath}
2657
+ `
2658
+ );
2659
+ return 0;
2660
+ }
2661
+ async executeMergeFiles() {
2662
+ this.context.stdout.write(`Merging OpenAPI files...
2663
+ `);
2664
+ let configPath = this.config || "api_docs";
2665
+ const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
2627
2666
  let final_api_docs = {};
2628
- for (let file_path of files_to_merge) {
2629
- let file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
2630
- final_api_docs = import_neko_helper3.Arr.deepMerge(final_api_docs, file_json);
2667
+ for (const file_path of files_to_merge) {
2668
+ try {
2669
+ const file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
2670
+ final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
2671
+ this.context.stdout.write(` Merged: ${file_path}
2672
+ `);
2673
+ } catch (error) {
2674
+ this.context.stderr.write(
2675
+ ` Warning: Could not read ${file_path}: ${error.message}
2676
+ `
2677
+ );
2678
+ }
2631
2679
  }
2632
- await fs6.writeFile(
2633
- config_exports.config.get("api_docs.output"),
2634
- JSON.stringify(final_api_docs, null, 2)
2635
- );
2680
+ const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
2681
+ await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
2682
+ await fs6.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
2636
2683
  this.context.stdout.write(
2637
- `wrote final open api document to : ${config_exports.config.get("api_docs.output")}
2684
+ `Final OpenAPI document written to: ${outputPath}
2638
2685
  `
2639
2686
  );
2687
+ return 0;
2640
2688
  }
2641
2689
  extractParameters(routePath) {
2642
2690
  const paramRegex = /:([a-zA-Z0-9_]+)/g;
@@ -2655,6 +2703,78 @@ var init_GenerateApiDocsCommand = __esm({
2655
2703
  }
2656
2704
  return parameters;
2657
2705
  }
2706
+ generateFromRoutes() {
2707
+ const openApiSpec = {
2708
+ paths: {}
2709
+ };
2710
+ const routes = router().routes;
2711
+ for (const route of routes) {
2712
+ const routePath = route.path;
2713
+ const openApiPath = routePath.replace(/\/$/g, "");
2714
+ if (!openApiSpec.paths[openApiPath]) {
2715
+ openApiSpec.paths[openApiPath] = {};
2716
+ }
2717
+ for (const method of route.methods) {
2718
+ const lowerMethod = method.toLowerCase();
2719
+ if (lowerMethod === "head") {
2720
+ continue;
2721
+ }
2722
+ openApiSpec.paths[openApiPath][lowerMethod] = {
2723
+ summary: `${routePath}`,
2724
+ description: `Endpoint for ${method} ${routePath}`,
2725
+ security: [],
2726
+ parameters: this.extractParameters(routePath),
2727
+ responses: {}
2728
+ };
2729
+ if (["post", "put", "patch"].includes(lowerMethod)) {
2730
+ openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
2731
+ required: true,
2732
+ content: {
2733
+ "application/json": {
2734
+ schema: {
2735
+ type: "object"
2736
+ }
2737
+ }
2738
+ }
2739
+ };
2740
+ }
2741
+ }
2742
+ }
2743
+ return openApiSpec;
2744
+ }
2745
+ getBaseOpenApiSpec() {
2746
+ const openApiSpec = {
2747
+ openapi: "3.0.0",
2748
+ info: {
2749
+ title: "API Documentation",
2750
+ version: "1.0.0",
2751
+ description: "Auto-generated API documentation"
2752
+ },
2753
+ servers: [
2754
+ {
2755
+ url: "/",
2756
+ description: "Local server"
2757
+ }
2758
+ ],
2759
+ components: {
2760
+ securitySchemes: {
2761
+ bearerAuth: {
2762
+ type: "http",
2763
+ scheme: "bearer",
2764
+ bearerFormat: "JWT",
2765
+ description: "JWT token authentication"
2766
+ }
2767
+ }
2768
+ },
2769
+ security: [
2770
+ {
2771
+ bearerAuth: []
2772
+ }
2773
+ ],
2774
+ paths: {}
2775
+ };
2776
+ return openApiSpec;
2777
+ }
2658
2778
  };
2659
2779
  cli().register(GenerateApiDocsCommand);
2660
2780
  }
@@ -3000,8 +3120,11 @@ var init_DatabaseServiceProvider = __esm({
3000
3120
  return _DatabaseServiceProvider.instance;
3001
3121
  }
3002
3122
  getConnection(db_config) {
3003
- const conn = new import_neko_sql2.PostgresqlConnection(db_config);
3004
- return conn;
3123
+ if (db_config.provider === "postgresql") {
3124
+ const conn = new import_neko_sql2.PostgresqlConnection(db_config.config);
3125
+ return conn;
3126
+ }
3127
+ throw new Error(`Unsupported database provider: ${db_config.provider}`);
3005
3128
  }
3006
3129
  };
3007
3130
  }