@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.
Files changed (41) hide show
  1. package/dist/DatabaseServiceProvider.d.mts +5 -2
  2. package/dist/DatabaseServiceProvider.mjs +10 -3
  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 +12 -2
  12. package/dist/bin/app/console/DefaultCommand.cjs +136 -69
  13. package/dist/bin/app/console/KeyGenerateCommand.cjs +136 -69
  14. package/dist/bin/app/console/StartCommand.cjs +141 -71
  15. package/dist/bin/app/console/generate/GenerateApiDocsCommand.cjs +320 -170
  16. package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +136 -69
  17. package/dist/bin/app/console/generate/index.cjs +320 -170
  18. package/dist/bin/app/console/index.cjs +325 -172
  19. package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +136 -69
  20. package/dist/bin/app/console/migrate/MigrateCommand.cjs +136 -69
  21. package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +136 -69
  22. package/dist/bin/app/console/migrate/index.cjs +136 -69
  23. package/dist/bin/app/console/queue/GenerateQueueMigrateCommand.cjs +136 -69
  24. package/dist/bin/cache.cjs +136 -69
  25. package/dist/bin/facades.cjs +136 -69
  26. package/dist/bin/factories.cjs +136 -69
  27. package/dist/bin/http.cjs +136 -69
  28. package/dist/bin/index.cjs +338 -178
  29. package/dist/bin/middlewares.cjs +136 -69
  30. package/dist/bin/queue.cjs +136 -69
  31. package/dist/bin/router.cjs +3 -5
  32. package/dist/facades.d.mts +6 -6
  33. package/dist/facades.mjs +97 -58
  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.mjs +1 -1
  38. package/dist/http.mjs.map +1 -1
  39. package/dist/queue.d.mts +1 -1
  40. package/dist/queue.mjs.map +1 -1
  41. 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 (this.isClass(middleware)) {
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_\.]/.test(path10[start])) {
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 import_neko_helper2 = require("@devbro/neko-helper");
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 import_neko_helper = require("@devbro/neko-helper");
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, import_neko_helper.createRepeater)(
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
- var router = (0, import_neko_helper2.createSingleton)(() => new Router());
1827
- var scheduler = (0, import_neko_helper2.createSingleton)(() => {
1828
- const rc = new import_neko_scheduler.Scheduler();
1829
- rc.setErrorHandler((err, job) => {
1830
- logger().error({
1831
- msg: "Scheduled job error",
1832
- err,
1833
- job_name: job.getName()
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
- return rc;
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 = (0, import_neko_helper2.createSingleton)((label = "default") => {
1840
- let storage_config = import_neko_config.config.get(["storages", label].join("."));
1841
- const provider = import_neko_storage2.StorageProviderFactory.create(
1842
- storage_config.provider,
1843
- storage_config.config
1844
- );
1845
- return new import_neko_storage2.Storage(provider);
1846
- });
1847
- var cli = (0, import_neko_helper2.createSingleton)(() => {
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, import_neko_helper2.createSingleton)(() => {
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 = (0, import_neko_helper2.createSingleton)((label) => {
1862
- const logger_config = import_neko_config.config.get(["loggers", label].join("."));
1863
- const rc = new import_neko_logger.Logger(logger_config);
1864
- rc.setExtrasFunction((message) => {
1865
- message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
1866
- return message;
1867
- });
1868
- return rc;
1869
- });
1870
- var mailer = (0, import_neko_helper2.createSingleton)((label) => {
1871
- const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
1872
- const provider = import_neko_mailer2.MailerProviderFactory.create(
1873
- mailer_config.provider,
1874
- mailer_config.config
1875
- );
1876
- const rc = new import_neko_mailer2.Mailer(provider);
1877
- return rc;
1878
- });
1879
- var queue = (0, import_neko_helper2.createSingleton)((label) => {
1880
- const queue_config = import_neko_config.config.get(["queues", label].join("."));
1881
- if (!queue_config) {
1882
- throw new Error(`Queue configuration for '${label}' not found`);
1883
- }
1884
- const provider = import_neko_queue2.QueueTransportFactory.create(
1885
- queue_config.provider,
1886
- queue_config.config
1887
- );
1888
- return new import_neko_queue2.QueueConnection(provider);
1889
- });
1890
- var cache = (0, import_neko_helper2.createSingleton)((label) => {
1891
- const cache_config = import_neko_config.config.get(["caches", label].join("."));
1892
- if (!cache_config) {
1893
- throw new Error(`Cache configuration for '${label}' not found`);
1894
- }
1895
- const provider = CacheProviderFactory.create(
1896
- cache_config.provider,
1897
- cache_config.config
1898
- );
1899
- return new import_neko_cache2.Cache(provider);
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((x) => x).length == 0) {
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 import_neko_helper3 = require("@devbro/neko-helper");
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
- The generated documentation includes:
2345
- - All registered routes with their HTTP methods
2346
- - Path parameters extracted from route definitions
2347
- - Request body schemas for POST, PUT, and PATCH methods
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
- api_docs: {
2355
- merge_files: [
2356
- path.join(__dirname, '../..', 'private', 'openapi_examples.json'),
2357
- path.join(__dirname, '../..', 'private', 'openapi_base.json'),
2358
- path.join(__dirname, '../..', 'private', 'openapi_user_changes.json'),
2359
- ],
2360
- output: path.join(__dirname, '../..', 'private', 'openapi.json'),
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: [[`Generate API documentation`, `$0 generate apidocs`]]
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
- help = import_clipanion9.Option.Boolean(`--help,-h`, false, {
2366
- description: `Show help message for this command`
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.help) {
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
- const rootDir = process.cwd();
2376
- this.context.stdout.write(`Generating OpenAPI documentation...
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
- const routes = router().routes;
2379
- const openApiSpec = {
2380
- openapi: "3.0.0",
2381
- info: {
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
- await fs6.mkdir(config_exports.config.get("private_path"), { recursive: true });
2440
- const outputPath = import_path7.default.join(config_exports.config.get("private_path"), "openapi.json");
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(`Total routes documented: ${routes.length}
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 files_to_merge = config_exports.config.get("api_docs.merge_files");
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 (let file_path of files_to_merge) {
2455
- let file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
2456
- final_api_docs = import_neko_helper3.Arr.deepMerge(final_api_docs, file_json);
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
- await fs6.writeFile(
2459
- config_exports.config.get("api_docs.output"),
2460
- JSON.stringify(final_api_docs, null, 2)
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
- `wrote final open api document to : ${config_exports.config.get("api_docs.output")}
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