@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.
- package/dist/DatabaseServiceProvider.d.mts +4 -1
- package/dist/DatabaseServiceProvider.mjs +5 -2
- package/dist/DatabaseServiceProvider.mjs.map +1 -1
- package/dist/app/console/StartCommand.d.mts +1 -0
- package/dist/app/console/StartCommand.mjs +5 -2
- package/dist/app/console/StartCommand.mjs.map +1 -1
- package/dist/app/console/generate/GenerateApiDocsCommand.d.mts +34 -2
- package/dist/app/console/generate/GenerateApiDocsCommand.mjs +183 -100
- package/dist/app/console/generate/GenerateApiDocsCommand.mjs.map +1 -1
- package/dist/app/console/project/base_project/src/config/storages.ts.tpl +2 -2
- package/dist/bin/DatabaseServiceProvider.cjs +8 -2
- package/dist/bin/app/console/DefaultCommand.cjs +64 -32
- package/dist/bin/app/console/KeyGenerateCommand.cjs +64 -32
- package/dist/bin/app/console/StartCommand.cjs +69 -34
- package/dist/bin/app/console/generate/GenerateApiDocsCommand.cjs +248 -133
- package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +64 -32
- package/dist/bin/app/console/generate/index.cjs +248 -133
- package/dist/bin/app/console/index.cjs +253 -135
- package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +64 -32
- package/dist/bin/app/console/migrate/MigrateCommand.cjs +64 -32
- package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +64 -32
- package/dist/bin/app/console/migrate/index.cjs +64 -32
- package/dist/bin/app/console/queue/GenerateQueueMigrateCommand.cjs +64 -32
- package/dist/bin/cache.cjs +64 -32
- package/dist/bin/facades.cjs +64 -32
- package/dist/bin/factories.cjs +64 -32
- package/dist/bin/http.cjs +739 -0
- package/dist/bin/index.cjs +264 -141
- package/dist/bin/middlewares.cjs +66 -34
- package/dist/bin/queue.cjs +64 -32
- package/dist/bin/router.cjs +4 -8
- package/dist/config.d.mts +0 -1
- package/dist/facades.mjs +2 -13
- package/dist/facades.mjs.map +1 -1
- package/dist/factories.mjs +45 -2
- package/dist/factories.mjs.map +1 -1
- package/dist/http.d.mts +4 -0
- package/dist/http.mjs +20 -0
- package/dist/http.mjs.map +1 -1
- package/dist/queue.d.mts +1 -1
- package/dist/queue.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -78,6 +78,7 @@ var MiddlewareFactory = class {
|
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
// ../neko-router/dist/CompiledRoute.mjs
|
|
81
|
+
var import_neko_helper = require("@devbro/neko-helper");
|
|
81
82
|
var CompiledRoute = class {
|
|
82
83
|
static {
|
|
83
84
|
__name(this, "CompiledRoute");
|
|
@@ -98,7 +99,7 @@ var CompiledRoute = class {
|
|
|
98
99
|
for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {
|
|
99
100
|
if (middleware instanceof Middleware) {
|
|
100
101
|
this.middlewares.push(middleware);
|
|
101
|
-
} else if (
|
|
102
|
+
} else if ((0, import_neko_helper.isClass)(middleware)) {
|
|
102
103
|
this.middlewares.push(middleware.getInstance({}));
|
|
103
104
|
} else if (typeof middleware === "function") {
|
|
104
105
|
this.middlewares.push(MiddlewareFactory.create(middleware));
|
|
@@ -107,13 +108,8 @@ var CompiledRoute = class {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
|
-
isClass(func) {
|
|
111
|
-
return typeof func === "function" && /^class\s/.test(Function.prototype.toString.call(func));
|
|
112
|
-
}
|
|
113
111
|
async run() {
|
|
114
|
-
|
|
115
|
-
this.response.end();
|
|
116
|
-
return rc;
|
|
112
|
+
return await this.runMiddlewares(this.middlewares, this.request, this.response);
|
|
117
113
|
}
|
|
118
114
|
prepareOutputJsonFormat(obj) {
|
|
119
115
|
function traverse(value) {
|
|
@@ -247,7 +243,7 @@ var Route = class {
|
|
|
247
243
|
i = start;
|
|
248
244
|
} else if (char === "*") {
|
|
249
245
|
let start = i + 1;
|
|
250
|
-
while (start < path4.length && /[a-zA-Z0-9_
|
|
246
|
+
while (start < path4.length && /[a-zA-Z0-9_]/.test(path4[start])) {
|
|
251
247
|
start++;
|
|
252
248
|
}
|
|
253
249
|
tokens.push({ type: "WILDCARD", value: path4.slice(i + 1, start) });
|
|
@@ -458,7 +454,7 @@ var Router = class {
|
|
|
458
454
|
|
|
459
455
|
// src/facades.mts
|
|
460
456
|
var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
461
|
-
var
|
|
457
|
+
var import_neko_helper3 = require("@devbro/neko-helper");
|
|
462
458
|
var import_neko_context3 = require("@devbro/neko-context");
|
|
463
459
|
var import_neko_storage2 = require("@devbro/neko-storage");
|
|
464
460
|
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
@@ -467,7 +463,24 @@ var import_clipanion = require("clipanion");
|
|
|
467
463
|
|
|
468
464
|
// src/http.mts
|
|
469
465
|
var http_exports = {};
|
|
466
|
+
__export(http_exports, {
|
|
467
|
+
handleHttpErrors: () => handleHttpErrors
|
|
468
|
+
});
|
|
469
|
+
var import_neko_http = require("@devbro/neko-http");
|
|
470
470
|
__reExport(http_exports, require("@devbro/neko-http"));
|
|
471
|
+
async function handleHttpErrors(err, req, res) {
|
|
472
|
+
if (err instanceof import_neko_http.HttpError) {
|
|
473
|
+
res.writeHead(err.statusCode, { "Content-Type": "application/json" });
|
|
474
|
+
res.write(JSON.stringify({ message: err.message, error: err.code }));
|
|
475
|
+
logger().warn({ msg: "HttpError: " + err.message, err });
|
|
476
|
+
return;
|
|
477
|
+
} else {
|
|
478
|
+
logger().error({ msg: "Error: " + err.message, err });
|
|
479
|
+
}
|
|
480
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
481
|
+
res.write(JSON.stringify({ error: "Internal Server Error" }));
|
|
482
|
+
}
|
|
483
|
+
__name(handleHttpErrors, "handleHttpErrors");
|
|
471
484
|
|
|
472
485
|
// src/facades.mts
|
|
473
486
|
var import_neko_logger = require("@devbro/neko-logger");
|
|
@@ -482,7 +495,7 @@ __export(queue_exports, {
|
|
|
482
495
|
DatabaseTransport: () => DatabaseTransport
|
|
483
496
|
});
|
|
484
497
|
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
485
|
-
var
|
|
498
|
+
var import_neko_helper2 = require("@devbro/neko-helper");
|
|
486
499
|
var import_neko_context2 = require("@devbro/neko-context");
|
|
487
500
|
var DatabaseTransport = class {
|
|
488
501
|
static {
|
|
@@ -543,7 +556,7 @@ var DatabaseTransport = class {
|
|
|
543
556
|
}, "processMessage");
|
|
544
557
|
constructor(config4 = {}) {
|
|
545
558
|
this.config = { ...this.config, ...config4 };
|
|
546
|
-
this.repeater = (0,
|
|
559
|
+
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
547
560
|
this.processMessage,
|
|
548
561
|
this.config.listen_interval * 1e3
|
|
549
562
|
);
|
|
@@ -611,6 +624,24 @@ import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
|
611
624
|
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
612
625
|
return new import_neko_queue.MemoryTransport(opt);
|
|
613
626
|
});
|
|
627
|
+
import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
|
|
628
|
+
return new import_neko_queue.AwsSqsTransport(opt);
|
|
629
|
+
});
|
|
630
|
+
import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
|
|
631
|
+
return new import_neko_queue.AmqpTransport(opt);
|
|
632
|
+
});
|
|
633
|
+
import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
|
|
634
|
+
return new import_neko_queue.RedisTransport(opt);
|
|
635
|
+
});
|
|
636
|
+
import_neko_queue.QueueTransportFactory.register("async", (opt) => {
|
|
637
|
+
return new import_neko_queue.AsyncTransport();
|
|
638
|
+
});
|
|
639
|
+
import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
|
|
640
|
+
return new import_neko_queue.AzureServiceBusTransport(opt);
|
|
641
|
+
});
|
|
642
|
+
import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
|
|
643
|
+
return new import_neko_queue.GooglePubSubTransport(opt);
|
|
644
|
+
});
|
|
614
645
|
var CacheProviderFactory = class _CacheProviderFactory {
|
|
615
646
|
static {
|
|
616
647
|
__name(this, "CacheProviderFactory");
|
|
@@ -641,12 +672,24 @@ import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
|
641
672
|
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
642
673
|
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
643
674
|
});
|
|
675
|
+
import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
|
|
676
|
+
return new import_neko_storage.GCPStorageProvider(opt);
|
|
677
|
+
});
|
|
678
|
+
import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
|
|
679
|
+
return new import_neko_storage.AzureBlobStorageProvider(opt);
|
|
680
|
+
});
|
|
681
|
+
import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
|
|
682
|
+
return new import_neko_storage.FTPStorageProvider(opt);
|
|
683
|
+
});
|
|
684
|
+
import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
|
|
685
|
+
return new import_neko_storage.SFTPStorageProvider(opt);
|
|
686
|
+
});
|
|
644
687
|
|
|
645
688
|
// src/facades.mts
|
|
646
689
|
var import_neko_cache2 = require("@devbro/neko-cache");
|
|
647
690
|
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
648
|
-
var router = (0,
|
|
649
|
-
var scheduler = (0,
|
|
691
|
+
var router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
692
|
+
var scheduler = (0, import_neko_helper3.createSingleton)(() => {
|
|
650
693
|
const rc = new import_neko_scheduler.Scheduler();
|
|
651
694
|
rc.setErrorHandler((err, job) => {
|
|
652
695
|
logger().error({
|
|
@@ -658,7 +701,7 @@ var scheduler = (0, import_neko_helper2.createSingleton)(() => {
|
|
|
658
701
|
return rc;
|
|
659
702
|
});
|
|
660
703
|
var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
661
|
-
var storage = (0,
|
|
704
|
+
var storage = (0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
662
705
|
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
663
706
|
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
664
707
|
storage_config.provider,
|
|
@@ -666,7 +709,7 @@ var storage = (0, import_neko_helper2.createSingleton)((label = "default") => {
|
|
|
666
709
|
);
|
|
667
710
|
return new import_neko_storage2.Storage(provider);
|
|
668
711
|
});
|
|
669
|
-
var cli = (0,
|
|
712
|
+
var cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
670
713
|
const [node, app, ...args] = process.argv;
|
|
671
714
|
return new import_clipanion.Cli({
|
|
672
715
|
binaryLabel: `My Application`,
|
|
@@ -674,24 +717,13 @@ var cli = (0, import_neko_helper2.createSingleton)(() => {
|
|
|
674
717
|
binaryVersion: `1.0.0`
|
|
675
718
|
});
|
|
676
719
|
});
|
|
677
|
-
var httpServer = (0,
|
|
720
|
+
var httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
678
721
|
const server = new http_exports.HttpServer();
|
|
679
|
-
server.setErrorHandler(
|
|
680
|
-
if (err instanceof http_exports.HttpError) {
|
|
681
|
-
res.writeHead(err.statusCode, { "Content-Type": "application/json" });
|
|
682
|
-
res.end(JSON.stringify({ message: err.message, error: err.code }));
|
|
683
|
-
logger().warn({ msg: "HttpError: " + err.message, err });
|
|
684
|
-
return;
|
|
685
|
-
} else {
|
|
686
|
-
logger().error({ msg: "Error: " + err.message, err });
|
|
687
|
-
}
|
|
688
|
-
res.writeHead(500, { "Content-Type": "" });
|
|
689
|
-
res.end(JSON.stringify({ error: "Internal Server Error" }));
|
|
690
|
-
});
|
|
722
|
+
server.setErrorHandler(handleHttpErrors);
|
|
691
723
|
server.setRouter(router());
|
|
692
724
|
return server;
|
|
693
725
|
});
|
|
694
|
-
var logger = (0,
|
|
726
|
+
var logger = (0, import_neko_helper3.createSingleton)((label) => {
|
|
695
727
|
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
696
728
|
const rc = new import_neko_logger.Logger(logger_config);
|
|
697
729
|
rc.setExtrasFunction((message) => {
|
|
@@ -700,7 +732,7 @@ var logger = (0, import_neko_helper2.createSingleton)((label) => {
|
|
|
700
732
|
});
|
|
701
733
|
return rc;
|
|
702
734
|
});
|
|
703
|
-
var mailer = (0,
|
|
735
|
+
var mailer = (0, import_neko_helper3.createSingleton)((label) => {
|
|
704
736
|
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
705
737
|
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
706
738
|
mailer_config.provider,
|
|
@@ -709,7 +741,7 @@ var mailer = (0, import_neko_helper2.createSingleton)((label) => {
|
|
|
709
741
|
const rc = new import_neko_mailer2.Mailer(provider);
|
|
710
742
|
return rc;
|
|
711
743
|
});
|
|
712
|
-
var queue = (0,
|
|
744
|
+
var queue = (0, import_neko_helper3.createSingleton)((label) => {
|
|
713
745
|
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
714
746
|
if (!queue_config) {
|
|
715
747
|
throw new Error(`Queue configuration for '${label}' not found`);
|
|
@@ -720,7 +752,7 @@ var queue = (0, import_neko_helper2.createSingleton)((label) => {
|
|
|
720
752
|
);
|
|
721
753
|
return new import_neko_queue2.QueueConnection(provider);
|
|
722
754
|
});
|
|
723
|
-
var cache = (0,
|
|
755
|
+
var cache = (0, import_neko_helper3.createSingleton)((label) => {
|
|
724
756
|
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
725
757
|
if (!cache_config) {
|
|
726
758
|
throw new Error(`Cache configuration for '${label}' not found`);
|
|
@@ -795,144 +827,155 @@ var config_exports = {};
|
|
|
795
827
|
__reExport(config_exports, require("@devbro/neko-config"));
|
|
796
828
|
|
|
797
829
|
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
798
|
-
var
|
|
830
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
799
831
|
var GenerateApiDocsCommand = class extends import_clipanion3.Command {
|
|
800
832
|
static {
|
|
801
833
|
__name(this, "GenerateApiDocsCommand");
|
|
802
834
|
}
|
|
803
|
-
static paths = [
|
|
804
|
-
[`make`, `apidocs`],
|
|
805
|
-
[`generate`, `apidocs`]
|
|
806
|
-
];
|
|
835
|
+
static paths = [[`generate`, `apidocsv2`]];
|
|
807
836
|
static usage = import_clipanion3.Command.Usage({
|
|
808
837
|
category: `Generate`,
|
|
809
838
|
description: `Generate OpenAPI documentation from routes`,
|
|
810
839
|
details: `
|
|
811
|
-
This command generates OpenAPI 3.0 specification documentation by analyzing
|
|
840
|
+
This command utility generates OpenAPI 3.0 specification documentation by analyzing
|
|
812
841
|
your application's routes and merging with example files.
|
|
813
842
|
|
|
814
|
-
|
|
815
|
-
-
|
|
816
|
-
-
|
|
817
|
-
-
|
|
818
|
-
- Response schemas
|
|
819
|
-
|
|
820
|
-
The command will merge files specified in config.api_docs.merge_files
|
|
821
|
-
and output the final documentation to config.api_docs.output.
|
|
843
|
+
Subcommands:
|
|
844
|
+
- generate-from-routes: Generate OpenAPI spec from registered routes
|
|
845
|
+
- generate-base: Generate base OpenAPI specification structure
|
|
846
|
+
- merge-files: Merge multiple OpenAPI files into final documentation
|
|
822
847
|
|
|
848
|
+
|
|
823
849
|
This command depends on config data. make sure your default config contains the following:
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
850
|
+
|
|
851
|
+
\`\`\`
|
|
852
|
+
api_docs: {
|
|
853
|
+
|
|
854
|
+
merge_files: [
|
|
855
|
+
|
|
856
|
+
path.join(__dirname, '../..', 'private', 'openapi_base.json'),
|
|
857
|
+
|
|
858
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),
|
|
859
|
+
|
|
860
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),
|
|
861
|
+
|
|
862
|
+
path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),
|
|
863
|
+
|
|
864
|
+
],
|
|
865
|
+
|
|
866
|
+
output: path.join(__dirname, '../..', 'public', 'openapi.json'),
|
|
867
|
+
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
\`\`\`
|
|
832
871
|
`,
|
|
833
|
-
examples: [
|
|
872
|
+
examples: [
|
|
873
|
+
[
|
|
874
|
+
`Generate from routes`,
|
|
875
|
+
`$0 generate apidocsv2 generate-from-routes --output path/to/output.json`
|
|
876
|
+
],
|
|
877
|
+
[
|
|
878
|
+
`Generate base spec`,
|
|
879
|
+
`$0 generate apidocsv2 generate-base --output path/to/output.json`
|
|
880
|
+
],
|
|
881
|
+
[`Merge files`, `$0 generate apidocsv2 merge-files`],
|
|
882
|
+
[`Show help`, `$0 generate apidocsv2 --help`]
|
|
883
|
+
]
|
|
884
|
+
});
|
|
885
|
+
subcommand = import_clipanion3.Option.String({ required: false });
|
|
886
|
+
output = import_clipanion3.Option.String(`--output,-o`, {
|
|
887
|
+
description: `Output file path for generated documentation`
|
|
834
888
|
});
|
|
835
|
-
|
|
836
|
-
description: `
|
|
889
|
+
config = import_clipanion3.Option.String(`--config,-c`, {
|
|
890
|
+
description: `Path in config to get details from (default: api_docs)`,
|
|
891
|
+
required: false
|
|
837
892
|
});
|
|
838
893
|
async execute() {
|
|
839
|
-
if (this.
|
|
894
|
+
if (!this.subcommand) {
|
|
840
895
|
this.context.stdout.write(
|
|
841
896
|
this.constructor.usage?.toString() || "No help available\n"
|
|
842
897
|
);
|
|
843
898
|
return 0;
|
|
844
899
|
}
|
|
845
|
-
|
|
846
|
-
|
|
900
|
+
switch (this.subcommand) {
|
|
901
|
+
case "generate-from-routes":
|
|
902
|
+
return await this.executeGenerateFromRoutes();
|
|
903
|
+
case "generate-base":
|
|
904
|
+
return await this.executeGenerateBase();
|
|
905
|
+
case "merge-files":
|
|
906
|
+
return await this.executeMergeFiles();
|
|
907
|
+
default:
|
|
908
|
+
this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
|
|
847
909
|
`);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
title: "API Documentation",
|
|
853
|
-
version: "1.0.0",
|
|
854
|
-
description: "Auto-generated API documentation"
|
|
855
|
-
},
|
|
856
|
-
servers: [
|
|
857
|
-
{
|
|
858
|
-
url: "/",
|
|
859
|
-
description: "Local server"
|
|
860
|
-
}
|
|
861
|
-
],
|
|
862
|
-
paths: {}
|
|
863
|
-
};
|
|
864
|
-
for (const route of routes) {
|
|
865
|
-
const routePath = route.path;
|
|
866
|
-
const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
|
|
867
|
-
if (!openApiSpec.paths[openApiPath]) {
|
|
868
|
-
openApiSpec.paths[openApiPath] = {};
|
|
869
|
-
}
|
|
870
|
-
for (const method of route.methods) {
|
|
871
|
-
const lowerMethod = method.toLowerCase();
|
|
872
|
-
if (lowerMethod === "head") {
|
|
873
|
-
continue;
|
|
874
|
-
}
|
|
875
|
-
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
876
|
-
summary: `${method} ${routePath}`,
|
|
877
|
-
description: `Endpoint for ${method} ${routePath}`,
|
|
878
|
-
parameters: this.extractParameters(routePath),
|
|
879
|
-
responses: {
|
|
880
|
-
"200": {
|
|
881
|
-
description: "Successful response",
|
|
882
|
-
content: {
|
|
883
|
-
"application/json": {
|
|
884
|
-
schema: {
|
|
885
|
-
type: "object"
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
},
|
|
890
|
-
"500": {
|
|
891
|
-
description: "Internal server error"
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
};
|
|
895
|
-
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
896
|
-
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
897
|
-
required: true,
|
|
898
|
-
content: {
|
|
899
|
-
"application/json": {
|
|
900
|
-
schema: {
|
|
901
|
-
type: "object"
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
};
|
|
906
|
-
}
|
|
907
|
-
}
|
|
910
|
+
this.context.stdout.write(
|
|
911
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
912
|
+
);
|
|
913
|
+
return 1;
|
|
908
914
|
}
|
|
909
|
-
|
|
910
|
-
|
|
915
|
+
}
|
|
916
|
+
async executeGenerateFromRoutes() {
|
|
917
|
+
this.context.stdout.write(
|
|
918
|
+
`Generating OpenAPI documentation from routes...
|
|
919
|
+
`
|
|
920
|
+
);
|
|
921
|
+
const openApiSpec = this.generateFromRoutes();
|
|
922
|
+
const outputPath = this.output || import_path3.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
923
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
911
924
|
await fs2.writeFile(
|
|
912
925
|
outputPath,
|
|
913
926
|
JSON.stringify(openApiSpec, null, 2),
|
|
914
927
|
"utf-8"
|
|
915
928
|
);
|
|
916
929
|
this.context.stdout.write(
|
|
917
|
-
`OpenAPI documentation generated at: ${outputPath}
|
|
930
|
+
`OpenAPI routes documentation generated at: ${outputPath}
|
|
931
|
+
`
|
|
932
|
+
);
|
|
933
|
+
this.context.stdout.write(
|
|
934
|
+
`Total routes documented: ${Object.keys(openApiSpec.paths).length}
|
|
935
|
+
`
|
|
936
|
+
);
|
|
937
|
+
return 0;
|
|
938
|
+
}
|
|
939
|
+
async executeGenerateBase() {
|
|
940
|
+
this.context.stdout.write(`Generating base OpenAPI specification...
|
|
941
|
+
`);
|
|
942
|
+
const baseSpec = this.getBaseOpenApiSpec();
|
|
943
|
+
const outputPath = this.output || import_path3.default.join(config_exports.config.get("private_path"), "openapi_base.json");
|
|
944
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
945
|
+
await fs2.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
|
|
946
|
+
this.context.stdout.write(
|
|
947
|
+
`Base OpenAPI specification generated at: ${outputPath}
|
|
918
948
|
`
|
|
919
949
|
);
|
|
920
|
-
|
|
950
|
+
return 0;
|
|
951
|
+
}
|
|
952
|
+
async executeMergeFiles() {
|
|
953
|
+
this.context.stdout.write(`Merging OpenAPI files...
|
|
921
954
|
`);
|
|
922
|
-
let
|
|
955
|
+
let configPath = this.config || "api_docs";
|
|
956
|
+
const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
|
|
923
957
|
let final_api_docs = {};
|
|
924
|
-
for (
|
|
925
|
-
|
|
926
|
-
|
|
958
|
+
for (const file_path of files_to_merge) {
|
|
959
|
+
try {
|
|
960
|
+
const file_json = JSON.parse(await fs2.readFile(file_path, "utf8"));
|
|
961
|
+
final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
|
|
962
|
+
this.context.stdout.write(` Merged: ${file_path}
|
|
963
|
+
`);
|
|
964
|
+
} catch (error) {
|
|
965
|
+
this.context.stderr.write(
|
|
966
|
+
` Warning: Could not read ${file_path}: ${error.message}
|
|
967
|
+
`
|
|
968
|
+
);
|
|
969
|
+
}
|
|
927
970
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
);
|
|
971
|
+
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
972
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
973
|
+
await fs2.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
932
974
|
this.context.stdout.write(
|
|
933
|
-
`
|
|
975
|
+
`Final OpenAPI document written to: ${outputPath}
|
|
934
976
|
`
|
|
935
977
|
);
|
|
978
|
+
return 0;
|
|
936
979
|
}
|
|
937
980
|
extractParameters(routePath) {
|
|
938
981
|
const paramRegex = /:([a-zA-Z0-9_]+)/g;
|
|
@@ -951,6 +994,78 @@ var GenerateApiDocsCommand = class extends import_clipanion3.Command {
|
|
|
951
994
|
}
|
|
952
995
|
return parameters;
|
|
953
996
|
}
|
|
997
|
+
generateFromRoutes() {
|
|
998
|
+
const openApiSpec = {
|
|
999
|
+
paths: {}
|
|
1000
|
+
};
|
|
1001
|
+
const routes = router().routes;
|
|
1002
|
+
for (const route of routes) {
|
|
1003
|
+
const routePath = route.path;
|
|
1004
|
+
const openApiPath = routePath.replace(/\/$/g, "");
|
|
1005
|
+
if (!openApiSpec.paths[openApiPath]) {
|
|
1006
|
+
openApiSpec.paths[openApiPath] = {};
|
|
1007
|
+
}
|
|
1008
|
+
for (const method of route.methods) {
|
|
1009
|
+
const lowerMethod = method.toLowerCase();
|
|
1010
|
+
if (lowerMethod === "head") {
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
1014
|
+
summary: `${routePath}`,
|
|
1015
|
+
description: `Endpoint for ${method} ${routePath}`,
|
|
1016
|
+
security: [],
|
|
1017
|
+
parameters: this.extractParameters(routePath),
|
|
1018
|
+
responses: {}
|
|
1019
|
+
};
|
|
1020
|
+
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
1021
|
+
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
1022
|
+
required: true,
|
|
1023
|
+
content: {
|
|
1024
|
+
"application/json": {
|
|
1025
|
+
schema: {
|
|
1026
|
+
type: "object"
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return openApiSpec;
|
|
1035
|
+
}
|
|
1036
|
+
getBaseOpenApiSpec() {
|
|
1037
|
+
const openApiSpec = {
|
|
1038
|
+
openapi: "3.0.0",
|
|
1039
|
+
info: {
|
|
1040
|
+
title: "API Documentation",
|
|
1041
|
+
version: "1.0.0",
|
|
1042
|
+
description: "Auto-generated API documentation"
|
|
1043
|
+
},
|
|
1044
|
+
servers: [
|
|
1045
|
+
{
|
|
1046
|
+
url: "/",
|
|
1047
|
+
description: "Local server"
|
|
1048
|
+
}
|
|
1049
|
+
],
|
|
1050
|
+
components: {
|
|
1051
|
+
securitySchemes: {
|
|
1052
|
+
bearerAuth: {
|
|
1053
|
+
type: "http",
|
|
1054
|
+
scheme: "bearer",
|
|
1055
|
+
bearerFormat: "JWT",
|
|
1056
|
+
description: "JWT token authentication"
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
security: [
|
|
1061
|
+
{
|
|
1062
|
+
bearerAuth: []
|
|
1063
|
+
}
|
|
1064
|
+
],
|
|
1065
|
+
paths: {}
|
|
1066
|
+
};
|
|
1067
|
+
return openApiSpec;
|
|
1068
|
+
}
|
|
954
1069
|
};
|
|
955
1070
|
cli().register(GenerateApiDocsCommand);
|
|
956
1071
|
// Annotate the CommonJS export names for ESM import in node:
|