@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
|
@@ -1241,6 +1241,7 @@ var MiddlewareFactory = class {
|
|
|
1241
1241
|
};
|
|
1242
1242
|
|
|
1243
1243
|
// ../neko-router/dist/CompiledRoute.mjs
|
|
1244
|
+
var import_neko_helper = require("@devbro/neko-helper");
|
|
1244
1245
|
var CompiledRoute = class {
|
|
1245
1246
|
static {
|
|
1246
1247
|
__name(this, "CompiledRoute");
|
|
@@ -1261,7 +1262,7 @@ var CompiledRoute = class {
|
|
|
1261
1262
|
for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {
|
|
1262
1263
|
if (middleware instanceof Middleware) {
|
|
1263
1264
|
this.middlewares.push(middleware);
|
|
1264
|
-
} else if (
|
|
1265
|
+
} else if ((0, import_neko_helper.isClass)(middleware)) {
|
|
1265
1266
|
this.middlewares.push(middleware.getInstance({}));
|
|
1266
1267
|
} else if (typeof middleware === "function") {
|
|
1267
1268
|
this.middlewares.push(MiddlewareFactory.create(middleware));
|
|
@@ -1270,9 +1271,6 @@ var CompiledRoute = class {
|
|
|
1270
1271
|
}
|
|
1271
1272
|
}
|
|
1272
1273
|
}
|
|
1273
|
-
isClass(func) {
|
|
1274
|
-
return typeof func === "function" && /^class\s/.test(Function.prototype.toString.call(func));
|
|
1275
|
-
}
|
|
1276
1274
|
async run() {
|
|
1277
1275
|
return await this.runMiddlewares(this.middlewares, this.request, this.response);
|
|
1278
1276
|
}
|
|
@@ -1408,7 +1406,7 @@ var Route = class {
|
|
|
1408
1406
|
i = start;
|
|
1409
1407
|
} else if (char === "*") {
|
|
1410
1408
|
let start = i + 1;
|
|
1411
|
-
while (start < path10.length && /[a-zA-Z0-9_
|
|
1409
|
+
while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
|
|
1412
1410
|
start++;
|
|
1413
1411
|
}
|
|
1414
1412
|
tokens.push({ type: "WILDCARD", value: path10.slice(i + 1, start) });
|
|
@@ -1619,7 +1617,7 @@ var Router = class {
|
|
|
1619
1617
|
|
|
1620
1618
|
// src/facades.mts
|
|
1621
1619
|
var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
1622
|
-
var
|
|
1620
|
+
var import_neko_helper3 = require("@devbro/neko-helper");
|
|
1623
1621
|
var import_neko_context3 = require("@devbro/neko-context");
|
|
1624
1622
|
var import_neko_storage2 = require("@devbro/neko-storage");
|
|
1625
1623
|
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
@@ -1660,7 +1658,7 @@ __export(queue_exports, {
|
|
|
1660
1658
|
DatabaseTransport: () => DatabaseTransport
|
|
1661
1659
|
});
|
|
1662
1660
|
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
1663
|
-
var
|
|
1661
|
+
var import_neko_helper2 = require("@devbro/neko-helper");
|
|
1664
1662
|
var import_neko_context2 = require("@devbro/neko-context");
|
|
1665
1663
|
var DatabaseTransport = class {
|
|
1666
1664
|
static {
|
|
@@ -1721,7 +1719,7 @@ var DatabaseTransport = class {
|
|
|
1721
1719
|
}, "processMessage");
|
|
1722
1720
|
constructor(config9 = {}) {
|
|
1723
1721
|
this.config = { ...this.config, ...config9 };
|
|
1724
|
-
this.repeater = (0,
|
|
1722
|
+
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
1725
1723
|
this.processMessage,
|
|
1726
1724
|
this.config.listen_interval * 1e3
|
|
1727
1725
|
);
|
|
@@ -1789,6 +1787,24 @@ import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
|
1789
1787
|
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
1790
1788
|
return new import_neko_queue.MemoryTransport(opt);
|
|
1791
1789
|
});
|
|
1790
|
+
import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
|
|
1791
|
+
return new import_neko_queue.AwsSqsTransport(opt);
|
|
1792
|
+
});
|
|
1793
|
+
import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
|
|
1794
|
+
return new import_neko_queue.AmqpTransport(opt);
|
|
1795
|
+
});
|
|
1796
|
+
import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
|
|
1797
|
+
return new import_neko_queue.RedisTransport(opt);
|
|
1798
|
+
});
|
|
1799
|
+
import_neko_queue.QueueTransportFactory.register("async", (opt) => {
|
|
1800
|
+
return new import_neko_queue.AsyncTransport();
|
|
1801
|
+
});
|
|
1802
|
+
import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
|
|
1803
|
+
return new import_neko_queue.AzureServiceBusTransport(opt);
|
|
1804
|
+
});
|
|
1805
|
+
import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
|
|
1806
|
+
return new import_neko_queue.GooglePubSubTransport(opt);
|
|
1807
|
+
});
|
|
1792
1808
|
var CacheProviderFactory = class _CacheProviderFactory {
|
|
1793
1809
|
static {
|
|
1794
1810
|
__name(this, "CacheProviderFactory");
|
|
@@ -1819,32 +1835,75 @@ import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
|
1819
1835
|
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
1820
1836
|
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
1821
1837
|
});
|
|
1838
|
+
import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
|
|
1839
|
+
return new import_neko_storage.GCPStorageProvider(opt);
|
|
1840
|
+
});
|
|
1841
|
+
import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
|
|
1842
|
+
return new import_neko_storage.AzureBlobStorageProvider(opt);
|
|
1843
|
+
});
|
|
1844
|
+
import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
|
|
1845
|
+
return new import_neko_storage.FTPStorageProvider(opt);
|
|
1846
|
+
});
|
|
1847
|
+
import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
|
|
1848
|
+
return new import_neko_storage.SFTPStorageProvider(opt);
|
|
1849
|
+
});
|
|
1822
1850
|
|
|
1823
1851
|
// src/facades.mts
|
|
1824
1852
|
var import_neko_cache2 = require("@devbro/neko-cache");
|
|
1825
1853
|
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
const
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1854
|
+
function wrapSingletonWithAccessors(singletonFn) {
|
|
1855
|
+
let methodsInitialized = false;
|
|
1856
|
+
const initializeMethods = /* @__PURE__ */ __name(() => {
|
|
1857
|
+
if (methodsInitialized) return;
|
|
1858
|
+
const defaultInstance = singletonFn();
|
|
1859
|
+
const prototype = Object.getPrototypeOf(defaultInstance);
|
|
1860
|
+
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
|
1861
|
+
(name) => name !== "constructor" && typeof prototype[name] === "function"
|
|
1862
|
+
);
|
|
1863
|
+
for (const methodName of methodNames) {
|
|
1864
|
+
singletonFn[methodName] = (...args) => {
|
|
1865
|
+
const instance = singletonFn();
|
|
1866
|
+
return instance[methodName](...args);
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1869
|
+
methodsInitialized = true;
|
|
1870
|
+
}, "initializeMethods");
|
|
1871
|
+
return new Proxy(singletonFn, {
|
|
1872
|
+
get(target, prop, receiver) {
|
|
1873
|
+
if (typeof prop === "string" && !Reflect.has(target, prop)) {
|
|
1874
|
+
initializeMethods();
|
|
1875
|
+
}
|
|
1876
|
+
return Reflect.get(target, prop, receiver);
|
|
1877
|
+
}
|
|
1835
1878
|
});
|
|
1836
|
-
|
|
1837
|
-
|
|
1879
|
+
}
|
|
1880
|
+
__name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
|
|
1881
|
+
var router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
1882
|
+
var scheduler = wrapSingletonWithAccessors(
|
|
1883
|
+
(0, import_neko_helper3.createSingleton)(() => {
|
|
1884
|
+
const rc = new import_neko_scheduler.Scheduler();
|
|
1885
|
+
rc.setErrorHandler((err, job) => {
|
|
1886
|
+
logger().error({
|
|
1887
|
+
msg: "Scheduled job error",
|
|
1888
|
+
err,
|
|
1889
|
+
job_name: job.getName()
|
|
1890
|
+
});
|
|
1891
|
+
});
|
|
1892
|
+
return rc;
|
|
1893
|
+
})
|
|
1894
|
+
);
|
|
1838
1895
|
var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
1839
|
-
var storage = (
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1896
|
+
var storage = wrapSingletonWithAccessors(
|
|
1897
|
+
(0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
1898
|
+
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
1899
|
+
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
1900
|
+
storage_config.provider,
|
|
1901
|
+
storage_config.config
|
|
1902
|
+
);
|
|
1903
|
+
return new import_neko_storage2.Storage(provider);
|
|
1904
|
+
})
|
|
1905
|
+
);
|
|
1906
|
+
var cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
1848
1907
|
const [node, app, ...args] = process.argv;
|
|
1849
1908
|
return new import_clipanion.Cli({
|
|
1850
1909
|
binaryLabel: `My Application`,
|
|
@@ -1852,52 +1911,60 @@ var cli = (0, import_neko_helper2.createSingleton)(() => {
|
|
|
1852
1911
|
binaryVersion: `1.0.0`
|
|
1853
1912
|
});
|
|
1854
1913
|
});
|
|
1855
|
-
var httpServer = (0,
|
|
1914
|
+
var httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
1856
1915
|
const server = new http_exports.HttpServer();
|
|
1857
1916
|
server.setErrorHandler(handleHttpErrors);
|
|
1858
1917
|
server.setRouter(router());
|
|
1859
1918
|
return server;
|
|
1860
1919
|
});
|
|
1861
|
-
var logger = (
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
mailer_config.config
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
queue_config.
|
|
1886
|
-
queue_config
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
});
|
|
1920
|
+
var logger = wrapSingletonWithAccessors(
|
|
1921
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1922
|
+
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
1923
|
+
const rc = new import_neko_logger.Logger(logger_config);
|
|
1924
|
+
rc.setExtrasFunction((message) => {
|
|
1925
|
+
message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
|
|
1926
|
+
return message;
|
|
1927
|
+
});
|
|
1928
|
+
return rc;
|
|
1929
|
+
})
|
|
1930
|
+
);
|
|
1931
|
+
var mailer = wrapSingletonWithAccessors(
|
|
1932
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1933
|
+
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
1934
|
+
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
1935
|
+
mailer_config.provider,
|
|
1936
|
+
mailer_config.config
|
|
1937
|
+
);
|
|
1938
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
1939
|
+
return rc;
|
|
1940
|
+
})
|
|
1941
|
+
);
|
|
1942
|
+
var queue = wrapSingletonWithAccessors(
|
|
1943
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1944
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
1945
|
+
if (!queue_config) {
|
|
1946
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
1947
|
+
}
|
|
1948
|
+
const provider = import_neko_queue2.QueueTransportFactory.create(
|
|
1949
|
+
queue_config.provider,
|
|
1950
|
+
queue_config.config
|
|
1951
|
+
);
|
|
1952
|
+
return new import_neko_queue2.QueueConnection(provider);
|
|
1953
|
+
})
|
|
1954
|
+
);
|
|
1955
|
+
var cache = wrapSingletonWithAccessors(
|
|
1956
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1957
|
+
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
1958
|
+
if (!cache_config) {
|
|
1959
|
+
throw new Error(`Cache configuration for '${label}' not found`);
|
|
1960
|
+
}
|
|
1961
|
+
const provider = CacheProviderFactory.create(
|
|
1962
|
+
cache_config.provider,
|
|
1963
|
+
cache_config.config
|
|
1964
|
+
);
|
|
1965
|
+
return new import_neko_cache2.Cache(provider);
|
|
1966
|
+
})
|
|
1967
|
+
);
|
|
1901
1968
|
|
|
1902
1969
|
// src/app/console/migrate/MigrateCommand.mts
|
|
1903
1970
|
var import_clipanion2 = require("clipanion");
|
|
@@ -2112,12 +2179,15 @@ var StartCommand = class extends import_clipanion5.Command {
|
|
|
2112
2179
|
__name(this, "StartCommand");
|
|
2113
2180
|
}
|
|
2114
2181
|
scheduler = import_clipanion5.Option.Boolean(`--scheduler`, false);
|
|
2182
|
+
cron = import_clipanion5.Option.Boolean(`--cron`, false);
|
|
2115
2183
|
http = import_clipanion5.Option.Boolean(`--http`, false);
|
|
2116
2184
|
queue = import_clipanion5.Option.Boolean(`--queue`, false);
|
|
2117
2185
|
all = import_clipanion5.Option.Boolean("--all", false);
|
|
2118
2186
|
static paths = [[`start`]];
|
|
2119
2187
|
async execute() {
|
|
2120
|
-
if ([this.all, this.http, this.scheduler, this.queue].filter(
|
|
2188
|
+
if ([this.all, this.http, this.scheduler || this.cron, this.queue].filter(
|
|
2189
|
+
(x) => x
|
|
2190
|
+
).length == 0) {
|
|
2121
2191
|
this.context.stdout.write(
|
|
2122
2192
|
`No service was selected. please check -h for details
|
|
2123
2193
|
`
|
|
@@ -2127,7 +2197,7 @@ var StartCommand = class extends import_clipanion5.Command {
|
|
|
2127
2197
|
logger().info(`Starting Server
|
|
2128
2198
|
`);
|
|
2129
2199
|
import_neko_sql.PostgresqlConnection.defaults.idleTimeoutMillis = 1e4;
|
|
2130
|
-
if (this.scheduler || this.all) {
|
|
2200
|
+
if (this.scheduler || this.cron || this.all) {
|
|
2131
2201
|
logger().info(`starting scheduler
|
|
2132
2202
|
`);
|
|
2133
2203
|
scheduler().start();
|
|
@@ -2325,144 +2395,155 @@ var config_exports = {};
|
|
|
2325
2395
|
__reExport(config_exports, require("@devbro/neko-config"));
|
|
2326
2396
|
|
|
2327
2397
|
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
2328
|
-
var
|
|
2398
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
2329
2399
|
var GenerateApiDocsCommand = class extends import_clipanion9.Command {
|
|
2330
2400
|
static {
|
|
2331
2401
|
__name(this, "GenerateApiDocsCommand");
|
|
2332
2402
|
}
|
|
2333
|
-
static paths = [
|
|
2334
|
-
[`make`, `apidocs`],
|
|
2335
|
-
[`generate`, `apidocs`]
|
|
2336
|
-
];
|
|
2403
|
+
static paths = [[`generate`, `apidocs`]];
|
|
2337
2404
|
static usage = import_clipanion9.Command.Usage({
|
|
2338
2405
|
category: `Generate`,
|
|
2339
2406
|
description: `Generate OpenAPI documentation from routes`,
|
|
2340
2407
|
details: `
|
|
2341
|
-
This command generates OpenAPI 3.0 specification documentation by analyzing
|
|
2408
|
+
This command utility generates OpenAPI 3.0 specification documentation by analyzing
|
|
2342
2409
|
your application's routes and merging with example files.
|
|
2343
2410
|
|
|
2344
|
-
|
|
2345
|
-
-
|
|
2346
|
-
-
|
|
2347
|
-
-
|
|
2348
|
-
- Response schemas
|
|
2349
|
-
|
|
2350
|
-
The command will merge files specified in config.api_docs.merge_files
|
|
2351
|
-
and output the final documentation to config.api_docs.output.
|
|
2411
|
+
Subcommands:
|
|
2412
|
+
- generate-from-routes: Generate OpenAPI spec from registered routes
|
|
2413
|
+
- generate-base: Generate base OpenAPI specification structure
|
|
2414
|
+
- merge-files: Merge multiple OpenAPI files into final documentation
|
|
2352
2415
|
|
|
2416
|
+
|
|
2353
2417
|
This command depends on config data. make sure your default config contains the following:
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2418
|
+
|
|
2419
|
+
\`\`\`
|
|
2420
|
+
api_docs: {
|
|
2421
|
+
|
|
2422
|
+
merge_files: [
|
|
2423
|
+
|
|
2424
|
+
path.join(__dirname, '../..', 'private', 'openapi_base.json'),
|
|
2425
|
+
|
|
2426
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),
|
|
2427
|
+
|
|
2428
|
+
path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),
|
|
2429
|
+
|
|
2430
|
+
path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),
|
|
2431
|
+
|
|
2432
|
+
],
|
|
2433
|
+
|
|
2434
|
+
output: path.join(__dirname, '../..', 'public', 'openapi.json'),
|
|
2435
|
+
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
\`\`\`
|
|
2362
2439
|
`,
|
|
2363
|
-
examples: [
|
|
2440
|
+
examples: [
|
|
2441
|
+
[
|
|
2442
|
+
`Generate from routes`,
|
|
2443
|
+
`$0 generate apidocs generate-from-routes --output path/to/output.json`
|
|
2444
|
+
],
|
|
2445
|
+
[
|
|
2446
|
+
`Generate base spec`,
|
|
2447
|
+
`$0 generate apidocs generate-base --output path/to/output.json`
|
|
2448
|
+
],
|
|
2449
|
+
[`Merge files`, `$0 generate apidocs merge-files`],
|
|
2450
|
+
[`Show help`, `$0 generate apidocs --help`]
|
|
2451
|
+
]
|
|
2452
|
+
});
|
|
2453
|
+
subcommand = import_clipanion9.Option.String({ required: false });
|
|
2454
|
+
output = import_clipanion9.Option.String(`--output,-o`, {
|
|
2455
|
+
description: `Output file path for generated documentation`
|
|
2364
2456
|
});
|
|
2365
|
-
|
|
2366
|
-
description: `
|
|
2457
|
+
config = import_clipanion9.Option.String(`--config,-c`, {
|
|
2458
|
+
description: `Path in config to get details from (default: api_docs)`,
|
|
2459
|
+
required: false
|
|
2367
2460
|
});
|
|
2368
2461
|
async execute() {
|
|
2369
|
-
if (this.
|
|
2462
|
+
if (!this.subcommand) {
|
|
2370
2463
|
this.context.stdout.write(
|
|
2371
2464
|
this.constructor.usage?.toString() || "No help available\n"
|
|
2372
2465
|
);
|
|
2373
2466
|
return 0;
|
|
2374
2467
|
}
|
|
2375
|
-
|
|
2376
|
-
|
|
2468
|
+
switch (this.subcommand) {
|
|
2469
|
+
case "generate-from-routes":
|
|
2470
|
+
return await this.executeGenerateFromRoutes();
|
|
2471
|
+
case "generate-base":
|
|
2472
|
+
return await this.executeGenerateBase();
|
|
2473
|
+
case "merge-files":
|
|
2474
|
+
return await this.executeMergeFiles();
|
|
2475
|
+
default:
|
|
2476
|
+
this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
|
|
2377
2477
|
`);
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
title: "API Documentation",
|
|
2383
|
-
version: "1.0.0",
|
|
2384
|
-
description: "Auto-generated API documentation"
|
|
2385
|
-
},
|
|
2386
|
-
servers: [
|
|
2387
|
-
{
|
|
2388
|
-
url: "/",
|
|
2389
|
-
description: "Local server"
|
|
2390
|
-
}
|
|
2391
|
-
],
|
|
2392
|
-
paths: {}
|
|
2393
|
-
};
|
|
2394
|
-
for (const route of routes) {
|
|
2395
|
-
const routePath = route.path;
|
|
2396
|
-
const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
|
|
2397
|
-
if (!openApiSpec.paths[openApiPath]) {
|
|
2398
|
-
openApiSpec.paths[openApiPath] = {};
|
|
2399
|
-
}
|
|
2400
|
-
for (const method of route.methods) {
|
|
2401
|
-
const lowerMethod = method.toLowerCase();
|
|
2402
|
-
if (lowerMethod === "head") {
|
|
2403
|
-
continue;
|
|
2404
|
-
}
|
|
2405
|
-
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
2406
|
-
summary: `${method} ${routePath}`,
|
|
2407
|
-
description: `Endpoint for ${method} ${routePath}`,
|
|
2408
|
-
parameters: this.extractParameters(routePath),
|
|
2409
|
-
responses: {
|
|
2410
|
-
"200": {
|
|
2411
|
-
description: "Successful response",
|
|
2412
|
-
content: {
|
|
2413
|
-
"application/json": {
|
|
2414
|
-
schema: {
|
|
2415
|
-
type: "object"
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
},
|
|
2420
|
-
"500": {
|
|
2421
|
-
description: "Internal server error"
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
};
|
|
2425
|
-
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
2426
|
-
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
2427
|
-
required: true,
|
|
2428
|
-
content: {
|
|
2429
|
-
"application/json": {
|
|
2430
|
-
schema: {
|
|
2431
|
-
type: "object"
|
|
2432
|
-
}
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
};
|
|
2436
|
-
}
|
|
2437
|
-
}
|
|
2478
|
+
this.context.stdout.write(
|
|
2479
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
2480
|
+
);
|
|
2481
|
+
return 1;
|
|
2438
2482
|
}
|
|
2439
|
-
|
|
2440
|
-
|
|
2483
|
+
}
|
|
2484
|
+
async executeGenerateFromRoutes() {
|
|
2485
|
+
this.context.stdout.write(
|
|
2486
|
+
`Generating OpenAPI documentation from routes...
|
|
2487
|
+
`
|
|
2488
|
+
);
|
|
2489
|
+
const openApiSpec = this.generateFromRoutes();
|
|
2490
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
2491
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2441
2492
|
await fs6.writeFile(
|
|
2442
2493
|
outputPath,
|
|
2443
2494
|
JSON.stringify(openApiSpec, null, 2),
|
|
2444
2495
|
"utf-8"
|
|
2445
2496
|
);
|
|
2446
2497
|
this.context.stdout.write(
|
|
2447
|
-
`OpenAPI documentation generated at: ${outputPath}
|
|
2498
|
+
`OpenAPI routes documentation generated at: ${outputPath}
|
|
2448
2499
|
`
|
|
2449
2500
|
);
|
|
2450
|
-
this.context.stdout.write(
|
|
2501
|
+
this.context.stdout.write(
|
|
2502
|
+
`Total routes documented: ${Object.keys(openApiSpec.paths).length}
|
|
2503
|
+
`
|
|
2504
|
+
);
|
|
2505
|
+
return 0;
|
|
2506
|
+
}
|
|
2507
|
+
async executeGenerateBase() {
|
|
2508
|
+
this.context.stdout.write(`Generating base OpenAPI specification...
|
|
2509
|
+
`);
|
|
2510
|
+
const baseSpec = this.getBaseOpenApiSpec();
|
|
2511
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_base.json");
|
|
2512
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2513
|
+
await fs6.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
|
|
2514
|
+
this.context.stdout.write(
|
|
2515
|
+
`Base OpenAPI specification generated at: ${outputPath}
|
|
2516
|
+
`
|
|
2517
|
+
);
|
|
2518
|
+
return 0;
|
|
2519
|
+
}
|
|
2520
|
+
async executeMergeFiles() {
|
|
2521
|
+
this.context.stdout.write(`Merging OpenAPI files...
|
|
2451
2522
|
`);
|
|
2452
|
-
let
|
|
2523
|
+
let configPath = this.config || "api_docs";
|
|
2524
|
+
const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
|
|
2453
2525
|
let final_api_docs = {};
|
|
2454
|
-
for (
|
|
2455
|
-
|
|
2456
|
-
|
|
2526
|
+
for (const file_path of files_to_merge) {
|
|
2527
|
+
try {
|
|
2528
|
+
const file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
|
|
2529
|
+
final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
|
|
2530
|
+
this.context.stdout.write(` Merged: ${file_path}
|
|
2531
|
+
`);
|
|
2532
|
+
} catch (error) {
|
|
2533
|
+
this.context.stderr.write(
|
|
2534
|
+
` Warning: Could not read ${file_path}: ${error.message}
|
|
2535
|
+
`
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2457
2538
|
}
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
);
|
|
2539
|
+
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
2540
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2541
|
+
await fs6.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
2462
2542
|
this.context.stdout.write(
|
|
2463
|
-
`
|
|
2543
|
+
`Final OpenAPI document written to: ${outputPath}
|
|
2464
2544
|
`
|
|
2465
2545
|
);
|
|
2546
|
+
return 0;
|
|
2466
2547
|
}
|
|
2467
2548
|
extractParameters(routePath) {
|
|
2468
2549
|
const paramRegex = /:([a-zA-Z0-9_]+)/g;
|
|
@@ -2481,6 +2562,78 @@ var GenerateApiDocsCommand = class extends import_clipanion9.Command {
|
|
|
2481
2562
|
}
|
|
2482
2563
|
return parameters;
|
|
2483
2564
|
}
|
|
2565
|
+
generateFromRoutes() {
|
|
2566
|
+
const openApiSpec = {
|
|
2567
|
+
paths: {}
|
|
2568
|
+
};
|
|
2569
|
+
const routes = router().routes;
|
|
2570
|
+
for (const route of routes) {
|
|
2571
|
+
const routePath = route.path;
|
|
2572
|
+
const openApiPath = routePath.replace(/\/$/g, "");
|
|
2573
|
+
if (!openApiSpec.paths[openApiPath]) {
|
|
2574
|
+
openApiSpec.paths[openApiPath] = {};
|
|
2575
|
+
}
|
|
2576
|
+
for (const method of route.methods) {
|
|
2577
|
+
const lowerMethod = method.toLowerCase();
|
|
2578
|
+
if (lowerMethod === "head") {
|
|
2579
|
+
continue;
|
|
2580
|
+
}
|
|
2581
|
+
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
2582
|
+
summary: `${routePath}`,
|
|
2583
|
+
description: `Endpoint for ${method} ${routePath}`,
|
|
2584
|
+
security: [],
|
|
2585
|
+
parameters: this.extractParameters(routePath),
|
|
2586
|
+
responses: {}
|
|
2587
|
+
};
|
|
2588
|
+
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
2589
|
+
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
2590
|
+
required: true,
|
|
2591
|
+
content: {
|
|
2592
|
+
"application/json": {
|
|
2593
|
+
schema: {
|
|
2594
|
+
type: "object"
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
return openApiSpec;
|
|
2603
|
+
}
|
|
2604
|
+
getBaseOpenApiSpec() {
|
|
2605
|
+
const openApiSpec = {
|
|
2606
|
+
openapi: "3.0.0",
|
|
2607
|
+
info: {
|
|
2608
|
+
title: "API Documentation",
|
|
2609
|
+
version: "1.0.0",
|
|
2610
|
+
description: "Auto-generated API documentation"
|
|
2611
|
+
},
|
|
2612
|
+
servers: [
|
|
2613
|
+
{
|
|
2614
|
+
url: "/",
|
|
2615
|
+
description: "Local server"
|
|
2616
|
+
}
|
|
2617
|
+
],
|
|
2618
|
+
components: {
|
|
2619
|
+
securitySchemes: {
|
|
2620
|
+
bearerAuth: {
|
|
2621
|
+
type: "http",
|
|
2622
|
+
scheme: "bearer",
|
|
2623
|
+
bearerFormat: "JWT",
|
|
2624
|
+
description: "JWT token authentication"
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
},
|
|
2628
|
+
security: [
|
|
2629
|
+
{
|
|
2630
|
+
bearerAuth: []
|
|
2631
|
+
}
|
|
2632
|
+
],
|
|
2633
|
+
paths: {}
|
|
2634
|
+
};
|
|
2635
|
+
return openApiSpec;
|
|
2636
|
+
}
|
|
2484
2637
|
};
|
|
2485
2638
|
cli().register(GenerateApiDocsCommand);
|
|
2486
2639
|
|