@devbro/pashmak 0.1.48 → 0.1.51
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 +5 -2
- package/dist/DatabaseServiceProvider.mjs +10 -3
- 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 +12 -2
- package/dist/bin/app/console/DefaultCommand.cjs +136 -69
- package/dist/bin/app/console/KeyGenerateCommand.cjs +136 -69
- package/dist/bin/app/console/StartCommand.cjs +141 -71
- package/dist/bin/app/console/generate/GenerateApiDocsCommand.cjs +320 -170
- package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +136 -69
- package/dist/bin/app/console/generate/index.cjs +320 -170
- package/dist/bin/app/console/index.cjs +325 -172
- package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +136 -69
- package/dist/bin/app/console/migrate/MigrateCommand.cjs +136 -69
- package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +136 -69
- package/dist/bin/app/console/migrate/index.cjs +136 -69
- package/dist/bin/app/console/queue/GenerateQueueMigrateCommand.cjs +136 -69
- package/dist/bin/cache.cjs +136 -69
- package/dist/bin/facades.cjs +136 -69
- package/dist/bin/factories.cjs +136 -69
- package/dist/bin/http.cjs +136 -69
- package/dist/bin/index.cjs +338 -178
- package/dist/bin/middlewares.cjs +136 -69
- package/dist/bin/queue.cjs +136 -69
- package/dist/bin/router.cjs +3 -5
- package/dist/facades.d.mts +6 -6
- package/dist/facades.mjs +97 -58
- package/dist/facades.mjs.map +1 -1
- package/dist/factories.mjs +45 -2
- package/dist/factories.mjs.map +1 -1
- package/dist/http.mjs +1 -1
- 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,9 +108,6 @@ 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
112
|
return await this.runMiddlewares(this.middlewares, this.request, this.response);
|
|
115
113
|
}
|
|
@@ -245,7 +243,7 @@ var Route = class {
|
|
|
245
243
|
i = start;
|
|
246
244
|
} else if (char === "*") {
|
|
247
245
|
let start = i + 1;
|
|
248
|
-
while (start < path4.length && /[a-zA-Z0-9_
|
|
246
|
+
while (start < path4.length && /[a-zA-Z0-9_]/.test(path4[start])) {
|
|
249
247
|
start++;
|
|
250
248
|
}
|
|
251
249
|
tokens.push({ type: "WILDCARD", value: path4.slice(i + 1, start) });
|
|
@@ -456,7 +454,7 @@ var Router = class {
|
|
|
456
454
|
|
|
457
455
|
// src/facades.mts
|
|
458
456
|
var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
459
|
-
var
|
|
457
|
+
var import_neko_helper3 = require("@devbro/neko-helper");
|
|
460
458
|
var import_neko_context3 = require("@devbro/neko-context");
|
|
461
459
|
var import_neko_storage2 = require("@devbro/neko-storage");
|
|
462
460
|
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
@@ -497,7 +495,7 @@ __export(queue_exports, {
|
|
|
497
495
|
DatabaseTransport: () => DatabaseTransport
|
|
498
496
|
});
|
|
499
497
|
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
500
|
-
var
|
|
498
|
+
var import_neko_helper2 = require("@devbro/neko-helper");
|
|
501
499
|
var import_neko_context2 = require("@devbro/neko-context");
|
|
502
500
|
var DatabaseTransport = class {
|
|
503
501
|
static {
|
|
@@ -558,7 +556,7 @@ var DatabaseTransport = class {
|
|
|
558
556
|
}, "processMessage");
|
|
559
557
|
constructor(config4 = {}) {
|
|
560
558
|
this.config = { ...this.config, ...config4 };
|
|
561
|
-
this.repeater = (0,
|
|
559
|
+
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
562
560
|
this.processMessage,
|
|
563
561
|
this.config.listen_interval * 1e3
|
|
564
562
|
);
|
|
@@ -626,6 +624,24 @@ import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
|
626
624
|
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
627
625
|
return new import_neko_queue.MemoryTransport(opt);
|
|
628
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
|
+
});
|
|
629
645
|
var CacheProviderFactory = class _CacheProviderFactory {
|
|
630
646
|
static {
|
|
631
647
|
__name(this, "CacheProviderFactory");
|
|
@@ -656,32 +672,75 @@ import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
|
656
672
|
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
657
673
|
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
658
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
|
+
});
|
|
659
687
|
|
|
660
688
|
// src/facades.mts
|
|
661
689
|
var import_neko_cache2 = require("@devbro/neko-cache");
|
|
662
690
|
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
691
|
+
function wrapSingletonWithAccessors(singletonFn) {
|
|
692
|
+
let methodsInitialized = false;
|
|
693
|
+
const initializeMethods = /* @__PURE__ */ __name(() => {
|
|
694
|
+
if (methodsInitialized) return;
|
|
695
|
+
const defaultInstance = singletonFn();
|
|
696
|
+
const prototype = Object.getPrototypeOf(defaultInstance);
|
|
697
|
+
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
|
698
|
+
(name) => name !== "constructor" && typeof prototype[name] === "function"
|
|
699
|
+
);
|
|
700
|
+
for (const methodName of methodNames) {
|
|
701
|
+
singletonFn[methodName] = (...args) => {
|
|
702
|
+
const instance = singletonFn();
|
|
703
|
+
return instance[methodName](...args);
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
methodsInitialized = true;
|
|
707
|
+
}, "initializeMethods");
|
|
708
|
+
return new Proxy(singletonFn, {
|
|
709
|
+
get(target, prop, receiver) {
|
|
710
|
+
if (typeof prop === "string" && !Reflect.has(target, prop)) {
|
|
711
|
+
initializeMethods();
|
|
712
|
+
}
|
|
713
|
+
return Reflect.get(target, prop, receiver);
|
|
714
|
+
}
|
|
672
715
|
});
|
|
673
|
-
|
|
674
|
-
|
|
716
|
+
}
|
|
717
|
+
__name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
|
|
718
|
+
var router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
719
|
+
var scheduler = wrapSingletonWithAccessors(
|
|
720
|
+
(0, import_neko_helper3.createSingleton)(() => {
|
|
721
|
+
const rc = new import_neko_scheduler.Scheduler();
|
|
722
|
+
rc.setErrorHandler((err, job) => {
|
|
723
|
+
logger().error({
|
|
724
|
+
msg: "Scheduled job error",
|
|
725
|
+
err,
|
|
726
|
+
job_name: job.getName()
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
return rc;
|
|
730
|
+
})
|
|
731
|
+
);
|
|
675
732
|
var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
676
|
-
var storage = (
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
733
|
+
var storage = wrapSingletonWithAccessors(
|
|
734
|
+
(0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
735
|
+
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
736
|
+
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
737
|
+
storage_config.provider,
|
|
738
|
+
storage_config.config
|
|
739
|
+
);
|
|
740
|
+
return new import_neko_storage2.Storage(provider);
|
|
741
|
+
})
|
|
742
|
+
);
|
|
743
|
+
var cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
685
744
|
const [node, app, ...args] = process.argv;
|
|
686
745
|
return new import_clipanion.Cli({
|
|
687
746
|
binaryLabel: `My Application`,
|
|
@@ -689,52 +748,60 @@ var cli = (0, import_neko_helper2.createSingleton)(() => {
|
|
|
689
748
|
binaryVersion: `1.0.0`
|
|
690
749
|
});
|
|
691
750
|
});
|
|
692
|
-
var httpServer = (0,
|
|
751
|
+
var httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
693
752
|
const server = new http_exports.HttpServer();
|
|
694
753
|
server.setErrorHandler(handleHttpErrors);
|
|
695
754
|
server.setRouter(router());
|
|
696
755
|
return server;
|
|
697
756
|
});
|
|
698
|
-
var logger = (
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
mailer_config.config
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
queue_config.
|
|
723
|
-
queue_config
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
});
|
|
757
|
+
var logger = wrapSingletonWithAccessors(
|
|
758
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
759
|
+
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
760
|
+
const rc = new import_neko_logger.Logger(logger_config);
|
|
761
|
+
rc.setExtrasFunction((message) => {
|
|
762
|
+
message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
|
|
763
|
+
return message;
|
|
764
|
+
});
|
|
765
|
+
return rc;
|
|
766
|
+
})
|
|
767
|
+
);
|
|
768
|
+
var mailer = wrapSingletonWithAccessors(
|
|
769
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
770
|
+
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
771
|
+
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
772
|
+
mailer_config.provider,
|
|
773
|
+
mailer_config.config
|
|
774
|
+
);
|
|
775
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
776
|
+
return rc;
|
|
777
|
+
})
|
|
778
|
+
);
|
|
779
|
+
var queue = wrapSingletonWithAccessors(
|
|
780
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
781
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
782
|
+
if (!queue_config) {
|
|
783
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
784
|
+
}
|
|
785
|
+
const provider = import_neko_queue2.QueueTransportFactory.create(
|
|
786
|
+
queue_config.provider,
|
|
787
|
+
queue_config.config
|
|
788
|
+
);
|
|
789
|
+
return new import_neko_queue2.QueueConnection(provider);
|
|
790
|
+
})
|
|
791
|
+
);
|
|
792
|
+
var cache = wrapSingletonWithAccessors(
|
|
793
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
794
|
+
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
795
|
+
if (!cache_config) {
|
|
796
|
+
throw new Error(`Cache configuration for '${label}' not found`);
|
|
797
|
+
}
|
|
798
|
+
const provider = CacheProviderFactory.create(
|
|
799
|
+
cache_config.provider,
|
|
800
|
+
cache_config.config
|
|
801
|
+
);
|
|
802
|
+
return new import_neko_cache2.Cache(provider);
|
|
803
|
+
})
|
|
804
|
+
);
|
|
738
805
|
|
|
739
806
|
// src/app/console/generate/GenerateControllerCommand.mts
|
|
740
807
|
var import_clipanion2 = require("clipanion");
|
|
@@ -799,144 +866,155 @@ var config_exports = {};
|
|
|
799
866
|
__reExport(config_exports, require("@devbro/neko-config"));
|
|
800
867
|
|
|
801
868
|
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
802
|
-
var
|
|
869
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
803
870
|
var GenerateApiDocsCommand = class extends import_clipanion3.Command {
|
|
804
871
|
static {
|
|
805
872
|
__name(this, "GenerateApiDocsCommand");
|
|
806
873
|
}
|
|
807
|
-
static paths = [
|
|
808
|
-
[`make`, `apidocs`],
|
|
809
|
-
[`generate`, `apidocs`]
|
|
810
|
-
];
|
|
874
|
+
static paths = [[`generate`, `apidocs`]];
|
|
811
875
|
static usage = import_clipanion3.Command.Usage({
|
|
812
876
|
category: `Generate`,
|
|
813
877
|
description: `Generate OpenAPI documentation from routes`,
|
|
814
878
|
details: `
|
|
815
|
-
This command generates OpenAPI 3.0 specification documentation by analyzing
|
|
879
|
+
This command utility generates OpenAPI 3.0 specification documentation by analyzing
|
|
816
880
|
your application's routes and merging with example files.
|
|
817
881
|
|
|
818
|
-
|
|
819
|
-
-
|
|
820
|
-
-
|
|
821
|
-
-
|
|
822
|
-
- Response schemas
|
|
823
|
-
|
|
824
|
-
The command will merge files specified in config.api_docs.merge_files
|
|
825
|
-
and output the final documentation to config.api_docs.output.
|
|
882
|
+
Subcommands:
|
|
883
|
+
- generate-from-routes: Generate OpenAPI spec from registered routes
|
|
884
|
+
- generate-base: Generate base OpenAPI specification structure
|
|
885
|
+
- merge-files: Merge multiple OpenAPI files into final documentation
|
|
826
886
|
|
|
887
|
+
|
|
827
888
|
This command depends on config data. make sure your default config contains the following:
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
889
|
+
|
|
890
|
+
\`\`\`
|
|
891
|
+
api_docs: {
|
|
892
|
+
|
|
893
|
+
merge_files: [
|
|
894
|
+
|
|
895
|
+
path.join(__dirname, '../..', 'private', 'openapi_base.json'),
|
|
896
|
+
|
|
897
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),
|
|
898
|
+
|
|
899
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),
|
|
900
|
+
|
|
901
|
+
path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),
|
|
902
|
+
|
|
903
|
+
],
|
|
904
|
+
|
|
905
|
+
output: path.join(__dirname, '../..', 'public', 'openapi.json'),
|
|
906
|
+
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
\`\`\`
|
|
836
910
|
`,
|
|
837
|
-
examples: [
|
|
911
|
+
examples: [
|
|
912
|
+
[
|
|
913
|
+
`Generate from routes`,
|
|
914
|
+
`$0 generate apidocs generate-from-routes --output path/to/output.json`
|
|
915
|
+
],
|
|
916
|
+
[
|
|
917
|
+
`Generate base spec`,
|
|
918
|
+
`$0 generate apidocs generate-base --output path/to/output.json`
|
|
919
|
+
],
|
|
920
|
+
[`Merge files`, `$0 generate apidocs merge-files`],
|
|
921
|
+
[`Show help`, `$0 generate apidocs --help`]
|
|
922
|
+
]
|
|
923
|
+
});
|
|
924
|
+
subcommand = import_clipanion3.Option.String({ required: false });
|
|
925
|
+
output = import_clipanion3.Option.String(`--output,-o`, {
|
|
926
|
+
description: `Output file path for generated documentation`
|
|
838
927
|
});
|
|
839
|
-
|
|
840
|
-
description: `
|
|
928
|
+
config = import_clipanion3.Option.String(`--config,-c`, {
|
|
929
|
+
description: `Path in config to get details from (default: api_docs)`,
|
|
930
|
+
required: false
|
|
841
931
|
});
|
|
842
932
|
async execute() {
|
|
843
|
-
if (this.
|
|
933
|
+
if (!this.subcommand) {
|
|
844
934
|
this.context.stdout.write(
|
|
845
935
|
this.constructor.usage?.toString() || "No help available\n"
|
|
846
936
|
);
|
|
847
937
|
return 0;
|
|
848
938
|
}
|
|
849
|
-
|
|
850
|
-
|
|
939
|
+
switch (this.subcommand) {
|
|
940
|
+
case "generate-from-routes":
|
|
941
|
+
return await this.executeGenerateFromRoutes();
|
|
942
|
+
case "generate-base":
|
|
943
|
+
return await this.executeGenerateBase();
|
|
944
|
+
case "merge-files":
|
|
945
|
+
return await this.executeMergeFiles();
|
|
946
|
+
default:
|
|
947
|
+
this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
|
|
851
948
|
`);
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
title: "API Documentation",
|
|
857
|
-
version: "1.0.0",
|
|
858
|
-
description: "Auto-generated API documentation"
|
|
859
|
-
},
|
|
860
|
-
servers: [
|
|
861
|
-
{
|
|
862
|
-
url: "/",
|
|
863
|
-
description: "Local server"
|
|
864
|
-
}
|
|
865
|
-
],
|
|
866
|
-
paths: {}
|
|
867
|
-
};
|
|
868
|
-
for (const route of routes) {
|
|
869
|
-
const routePath = route.path;
|
|
870
|
-
const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
|
|
871
|
-
if (!openApiSpec.paths[openApiPath]) {
|
|
872
|
-
openApiSpec.paths[openApiPath] = {};
|
|
873
|
-
}
|
|
874
|
-
for (const method of route.methods) {
|
|
875
|
-
const lowerMethod = method.toLowerCase();
|
|
876
|
-
if (lowerMethod === "head") {
|
|
877
|
-
continue;
|
|
878
|
-
}
|
|
879
|
-
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
880
|
-
summary: `${method} ${routePath}`,
|
|
881
|
-
description: `Endpoint for ${method} ${routePath}`,
|
|
882
|
-
parameters: this.extractParameters(routePath),
|
|
883
|
-
responses: {
|
|
884
|
-
"200": {
|
|
885
|
-
description: "Successful response",
|
|
886
|
-
content: {
|
|
887
|
-
"application/json": {
|
|
888
|
-
schema: {
|
|
889
|
-
type: "object"
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
},
|
|
894
|
-
"500": {
|
|
895
|
-
description: "Internal server error"
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
};
|
|
899
|
-
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
900
|
-
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
901
|
-
required: true,
|
|
902
|
-
content: {
|
|
903
|
-
"application/json": {
|
|
904
|
-
schema: {
|
|
905
|
-
type: "object"
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
}
|
|
949
|
+
this.context.stdout.write(
|
|
950
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
951
|
+
);
|
|
952
|
+
return 1;
|
|
912
953
|
}
|
|
913
|
-
|
|
914
|
-
|
|
954
|
+
}
|
|
955
|
+
async executeGenerateFromRoutes() {
|
|
956
|
+
this.context.stdout.write(
|
|
957
|
+
`Generating OpenAPI documentation from routes...
|
|
958
|
+
`
|
|
959
|
+
);
|
|
960
|
+
const openApiSpec = this.generateFromRoutes();
|
|
961
|
+
const outputPath = this.output || import_path3.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
962
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
915
963
|
await fs2.writeFile(
|
|
916
964
|
outputPath,
|
|
917
965
|
JSON.stringify(openApiSpec, null, 2),
|
|
918
966
|
"utf-8"
|
|
919
967
|
);
|
|
920
968
|
this.context.stdout.write(
|
|
921
|
-
`OpenAPI documentation generated at: ${outputPath}
|
|
969
|
+
`OpenAPI routes documentation generated at: ${outputPath}
|
|
970
|
+
`
|
|
971
|
+
);
|
|
972
|
+
this.context.stdout.write(
|
|
973
|
+
`Total routes documented: ${Object.keys(openApiSpec.paths).length}
|
|
974
|
+
`
|
|
975
|
+
);
|
|
976
|
+
return 0;
|
|
977
|
+
}
|
|
978
|
+
async executeGenerateBase() {
|
|
979
|
+
this.context.stdout.write(`Generating base OpenAPI specification...
|
|
980
|
+
`);
|
|
981
|
+
const baseSpec = this.getBaseOpenApiSpec();
|
|
982
|
+
const outputPath = this.output || import_path3.default.join(config_exports.config.get("private_path"), "openapi_base.json");
|
|
983
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
984
|
+
await fs2.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
|
|
985
|
+
this.context.stdout.write(
|
|
986
|
+
`Base OpenAPI specification generated at: ${outputPath}
|
|
922
987
|
`
|
|
923
988
|
);
|
|
924
|
-
|
|
989
|
+
return 0;
|
|
990
|
+
}
|
|
991
|
+
async executeMergeFiles() {
|
|
992
|
+
this.context.stdout.write(`Merging OpenAPI files...
|
|
925
993
|
`);
|
|
926
|
-
let
|
|
994
|
+
let configPath = this.config || "api_docs";
|
|
995
|
+
const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
|
|
927
996
|
let final_api_docs = {};
|
|
928
|
-
for (
|
|
929
|
-
|
|
930
|
-
|
|
997
|
+
for (const file_path of files_to_merge) {
|
|
998
|
+
try {
|
|
999
|
+
const file_json = JSON.parse(await fs2.readFile(file_path, "utf8"));
|
|
1000
|
+
final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
|
|
1001
|
+
this.context.stdout.write(` Merged: ${file_path}
|
|
1002
|
+
`);
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
this.context.stderr.write(
|
|
1005
|
+
` Warning: Could not read ${file_path}: ${error.message}
|
|
1006
|
+
`
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
931
1009
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
);
|
|
1010
|
+
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
1011
|
+
await fs2.mkdir(import_path3.default.dirname(outputPath), { recursive: true });
|
|
1012
|
+
await fs2.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
936
1013
|
this.context.stdout.write(
|
|
937
|
-
`
|
|
1014
|
+
`Final OpenAPI document written to: ${outputPath}
|
|
938
1015
|
`
|
|
939
1016
|
);
|
|
1017
|
+
return 0;
|
|
940
1018
|
}
|
|
941
1019
|
extractParameters(routePath) {
|
|
942
1020
|
const paramRegex = /:([a-zA-Z0-9_]+)/g;
|
|
@@ -955,6 +1033,78 @@ var GenerateApiDocsCommand = class extends import_clipanion3.Command {
|
|
|
955
1033
|
}
|
|
956
1034
|
return parameters;
|
|
957
1035
|
}
|
|
1036
|
+
generateFromRoutes() {
|
|
1037
|
+
const openApiSpec = {
|
|
1038
|
+
paths: {}
|
|
1039
|
+
};
|
|
1040
|
+
const routes = router().routes;
|
|
1041
|
+
for (const route of routes) {
|
|
1042
|
+
const routePath = route.path;
|
|
1043
|
+
const openApiPath = routePath.replace(/\/$/g, "");
|
|
1044
|
+
if (!openApiSpec.paths[openApiPath]) {
|
|
1045
|
+
openApiSpec.paths[openApiPath] = {};
|
|
1046
|
+
}
|
|
1047
|
+
for (const method of route.methods) {
|
|
1048
|
+
const lowerMethod = method.toLowerCase();
|
|
1049
|
+
if (lowerMethod === "head") {
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
1053
|
+
summary: `${routePath}`,
|
|
1054
|
+
description: `Endpoint for ${method} ${routePath}`,
|
|
1055
|
+
security: [],
|
|
1056
|
+
parameters: this.extractParameters(routePath),
|
|
1057
|
+
responses: {}
|
|
1058
|
+
};
|
|
1059
|
+
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
1060
|
+
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
1061
|
+
required: true,
|
|
1062
|
+
content: {
|
|
1063
|
+
"application/json": {
|
|
1064
|
+
schema: {
|
|
1065
|
+
type: "object"
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return openApiSpec;
|
|
1074
|
+
}
|
|
1075
|
+
getBaseOpenApiSpec() {
|
|
1076
|
+
const openApiSpec = {
|
|
1077
|
+
openapi: "3.0.0",
|
|
1078
|
+
info: {
|
|
1079
|
+
title: "API Documentation",
|
|
1080
|
+
version: "1.0.0",
|
|
1081
|
+
description: "Auto-generated API documentation"
|
|
1082
|
+
},
|
|
1083
|
+
servers: [
|
|
1084
|
+
{
|
|
1085
|
+
url: "/",
|
|
1086
|
+
description: "Local server"
|
|
1087
|
+
}
|
|
1088
|
+
],
|
|
1089
|
+
components: {
|
|
1090
|
+
securitySchemes: {
|
|
1091
|
+
bearerAuth: {
|
|
1092
|
+
type: "http",
|
|
1093
|
+
scheme: "bearer",
|
|
1094
|
+
bearerFormat: "JWT",
|
|
1095
|
+
description: "JWT token authentication"
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
},
|
|
1099
|
+
security: [
|
|
1100
|
+
{
|
|
1101
|
+
bearerAuth: []
|
|
1102
|
+
}
|
|
1103
|
+
],
|
|
1104
|
+
paths: {}
|
|
1105
|
+
};
|
|
1106
|
+
return openApiSpec;
|
|
1107
|
+
}
|
|
958
1108
|
};
|
|
959
1109
|
cli().register(GenerateApiDocsCommand);
|
|
960
1110
|
// Annotate the CommonJS export names for ESM import in node:
|