@devbro/pashmak 0.1.49 → 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 (29) hide show
  1. package/dist/DatabaseServiceProvider.d.mts +2 -2
  2. package/dist/DatabaseServiceProvider.mjs +5 -1
  3. package/dist/DatabaseServiceProvider.mjs.map +1 -1
  4. package/dist/app/console/generate/GenerateApiDocsCommand.mjs +5 -5
  5. package/dist/app/console/generate/GenerateApiDocsCommand.mjs.map +1 -1
  6. package/dist/bin/DatabaseServiceProvider.cjs +4 -0
  7. package/dist/bin/app/console/DefaultCommand.cjs +97 -58
  8. package/dist/bin/app/console/KeyGenerateCommand.cjs +97 -58
  9. package/dist/bin/app/console/StartCommand.cjs +97 -58
  10. package/dist/bin/app/console/generate/GenerateApiDocsCommand.cjs +102 -63
  11. package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +97 -58
  12. package/dist/bin/app/console/generate/index.cjs +102 -63
  13. package/dist/bin/app/console/index.cjs +102 -63
  14. package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +97 -58
  15. package/dist/bin/app/console/migrate/MigrateCommand.cjs +97 -58
  16. package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +97 -58
  17. package/dist/bin/app/console/migrate/index.cjs +97 -58
  18. package/dist/bin/app/console/queue/GenerateQueueMigrateCommand.cjs +97 -58
  19. package/dist/bin/cache.cjs +97 -58
  20. package/dist/bin/facades.cjs +97 -58
  21. package/dist/bin/factories.cjs +97 -58
  22. package/dist/bin/http.cjs +97 -58
  23. package/dist/bin/index.cjs +106 -63
  24. package/dist/bin/middlewares.cjs +97 -58
  25. package/dist/bin/queue.cjs +97 -58
  26. package/dist/facades.d.mts +6 -6
  27. package/dist/facades.mjs +97 -58
  28. package/dist/facades.mjs.map +1 -1
  29. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { Middleware, Request, Response } from '@devbro/neko-router';
2
+ import { SqliteConfig, Connection } from '@devbro/neko-sql';
2
3
  import { PoolConfig } from 'pg';
3
- import { Connection } from '@devbro/neko-sql';
4
4
 
5
5
  declare class DatabaseServiceProvider extends Middleware {
6
6
  call(req: Request, res: Response, next: () => Promise<void>): Promise<void>;
@@ -9,7 +9,7 @@ declare class DatabaseServiceProvider extends Middleware {
9
9
  static getInstance(): DatabaseServiceProvider;
10
10
  getConnection(db_config: {
11
11
  provider: string;
12
- config: PoolConfig;
12
+ config: PoolConfig | SqliteConfig;
13
13
  }): Connection;
14
14
  }
15
15
 
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { Middleware } from "@devbro/neko-router";
4
- import { PostgresqlConnection } from "@devbro/neko-sql";
4
+ import { PostgresqlConnection, SqliteConnection } from "@devbro/neko-sql";
5
5
  import { BaseModel } from "@devbro/neko-orm";
6
6
  import { ctx } from "@devbro/neko-context";
7
7
  import { config } from "@devbro/neko-config";
@@ -53,6 +53,10 @@ class DatabaseServiceProvider extends Middleware {
53
53
  const conn = new PostgresqlConnection(db_config.config);
54
54
  return conn;
55
55
  }
56
+ if (db_config.provider === "sqlite") {
57
+ const conn = new SqliteConnection(db_config.config);
58
+ return conn;
59
+ }
56
60
  throw new Error(`Unsupported database provider: ${db_config.provider}`);
57
61
  }
58
62
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/DatabaseServiceProvider.mts"],"sourcesContent":["import { Middleware } from \"@devbro/neko-router\";\nimport { Request, Response } from \"@devbro/neko-router\";\nimport { PostgresqlConnection } from \"@devbro/neko-sql\";\nimport { PoolConfig } from \"pg\";\nimport { Connection } from \"@devbro/neko-sql\";\nimport { BaseModel } from \"@devbro/neko-orm\";\nimport { ctx } from \"@devbro/neko-context\";\nimport { config } from \"@devbro/neko-config\";\nimport { Global } from \"./global.mjs\";\n\nexport class DatabaseServiceProvider extends Middleware {\n async call(\n req: Request,\n res: Response,\n next: () => Promise<void>,\n ): Promise<void> {\n const db_configs: Record<string, { provider: string; config: PoolConfig }> =\n config.get(\"databases\");\n\n const conns = [];\n try {\n for (const [name, db_config] of Object.entries(db_configs)) {\n const conn = await this.getConnection(db_config);\n ctx().set([\"database\", name], conn);\n conns.push(conn);\n }\n BaseModel.setConnection(() => {\n const key = [\"database\", \"default\"];\n let rc: Connection | undefined;\n\n if (ctx.isActive()) {\n rc = ctx().get<Connection>(key);\n } else if (Global.has(key)) {\n rc = Global.get<Connection>(key);\n } else {\n rc = this.getConnection(db_configs[\"default\"]);\n Global.set(key, rc);\n }\n\n return rc!;\n });\n await next();\n } finally {\n for (const conn of conns) {\n await conn.disconnect();\n }\n }\n }\n\n private static instance: DatabaseServiceProvider;\n\n async register(): Promise<void> {}\n\n static getInstance(): DatabaseServiceProvider {\n if (!DatabaseServiceProvider.instance) {\n DatabaseServiceProvider.instance = new DatabaseServiceProvider();\n }\n return DatabaseServiceProvider.instance;\n }\n\n getConnection(db_config: {\n provider: string;\n config: PoolConfig;\n }): Connection {\n if (db_config.provider === \"postgresql\") {\n const conn = new PostgresqlConnection(db_config.config);\n return conn;\n }\n\n throw new Error(`Unsupported database provider: ${db_config.provider}`);\n }\n}\n"],"mappings":";;AAAA,SAAS,kBAAkB;AAE3B,SAAS,4BAA4B;AAGrC,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;AACvB,SAAS,cAAc;AAEhB,MAAM,gCAAgC,WAAW;AAAA,EAVxD,OAUwD;AAAA;AAAA;AAAA,EACtD,MAAM,KACJ,KACA,KACA,MACe;AACf,UAAM,aACJ,OAAO,IAAI,WAAW;AAExB,UAAM,QAAQ,CAAC;AACf,QAAI;AACF,iBAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC1D,cAAM,OAAO,MAAM,KAAK,cAAc,SAAS;AAC/C,YAAI,EAAE,IAAI,CAAC,YAAY,IAAI,GAAG,IAAI;AAClC,cAAM,KAAK,IAAI;AAAA,MACjB;AACA,gBAAU,cAAc,MAAM;AAC5B,cAAM,MAAM,CAAC,YAAY,SAAS;AAClC,YAAI;AAEJ,YAAI,IAAI,SAAS,GAAG;AAClB,eAAK,IAAI,EAAE,IAAgB,GAAG;AAAA,QAChC,WAAW,OAAO,IAAI,GAAG,GAAG;AAC1B,eAAK,OAAO,IAAgB,GAAG;AAAA,QACjC,OAAO;AACL,eAAK,KAAK,cAAc,WAAW,SAAS,CAAC;AAC7C,iBAAO,IAAI,KAAK,EAAE;AAAA,QACpB;AAEA,eAAO;AAAA,MACT,CAAC;AACD,YAAM,KAAK;AAAA,IACb,UAAE;AACA,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,WAAW;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAe;AAAA,EAEf,MAAM,WAA0B;AAAA,EAAC;AAAA,EAEjC,OAAO,cAAuC;AAC5C,QAAI,CAAC,wBAAwB,UAAU;AACrC,8BAAwB,WAAW,IAAI,wBAAwB;AAAA,IACjE;AACA,WAAO,wBAAwB;AAAA,EACjC;AAAA,EAEA,cAAc,WAGC;AACb,QAAI,UAAU,aAAa,cAAc;AACvC,YAAM,OAAO,IAAI,qBAAqB,UAAU,MAAM;AACtD,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,MAAM,kCAAkC,UAAU,QAAQ,EAAE;AAAA,EACxE;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/DatabaseServiceProvider.mts"],"sourcesContent":["import { Middleware } from \"@devbro/neko-router\";\nimport { Request, Response } from \"@devbro/neko-router\";\nimport { PostgresqlConnection, SqliteConnection, SqliteConfig } from \"@devbro/neko-sql\";\nimport { PoolConfig } from \"pg\";\nimport { Connection } from \"@devbro/neko-sql\";\nimport { BaseModel } from \"@devbro/neko-orm\";\nimport { ctx } from \"@devbro/neko-context\";\nimport { config } from \"@devbro/neko-config\";\nimport { Global } from \"./global.mjs\";\n\nexport class DatabaseServiceProvider extends Middleware {\n async call(\n req: Request,\n res: Response,\n next: () => Promise<void>,\n ): Promise<void> {\n const db_configs: Record<string, { provider: string; config: PoolConfig | SqliteConfig }> =\n config.get(\"databases\");\n\n const conns = [];\n try {\n for (const [name, db_config] of Object.entries(db_configs)) {\n const conn = await this.getConnection(db_config);\n ctx().set([\"database\", name], conn);\n conns.push(conn);\n }\n BaseModel.setConnection(() => {\n const key = [\"database\", \"default\"];\n let rc: Connection | undefined;\n\n if (ctx.isActive()) {\n rc = ctx().get<Connection>(key);\n } else if (Global.has(key)) {\n rc = Global.get<Connection>(key);\n } else {\n rc = this.getConnection(db_configs[\"default\"]);\n Global.set(key, rc);\n }\n\n return rc!;\n });\n await next();\n } finally {\n for (const conn of conns) {\n await conn.disconnect();\n }\n }\n }\n\n private static instance: DatabaseServiceProvider;\n\n async register(): Promise<void> {}\n\n static getInstance(): DatabaseServiceProvider {\n if (!DatabaseServiceProvider.instance) {\n DatabaseServiceProvider.instance = new DatabaseServiceProvider();\n }\n return DatabaseServiceProvider.instance;\n }\n\n getConnection(db_config: {\n provider: string;\n config: PoolConfig | SqliteConfig;\n }): Connection {\n if (db_config.provider === \"postgresql\") {\n const conn = new PostgresqlConnection(db_config.config as PoolConfig);\n return conn;\n }\n\n if (db_config.provider === \"sqlite\") {\n const conn = new SqliteConnection(db_config.config as SqliteConfig);\n return conn;\n }\n\n throw new Error(`Unsupported database provider: ${db_config.provider}`);\n }\n}\n"],"mappings":";;AAAA,SAAS,kBAAkB;AAE3B,SAAS,sBAAsB,wBAAsC;AAGrE,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;AACvB,SAAS,cAAc;AAEhB,MAAM,gCAAgC,WAAW;AAAA,EAVxD,OAUwD;AAAA;AAAA;AAAA,EACtD,MAAM,KACJ,KACA,KACA,MACe;AACf,UAAM,aACJ,OAAO,IAAI,WAAW;AAExB,UAAM,QAAQ,CAAC;AACf,QAAI;AACF,iBAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC1D,cAAM,OAAO,MAAM,KAAK,cAAc,SAAS;AAC/C,YAAI,EAAE,IAAI,CAAC,YAAY,IAAI,GAAG,IAAI;AAClC,cAAM,KAAK,IAAI;AAAA,MACjB;AACA,gBAAU,cAAc,MAAM;AAC5B,cAAM,MAAM,CAAC,YAAY,SAAS;AAClC,YAAI;AAEJ,YAAI,IAAI,SAAS,GAAG;AAClB,eAAK,IAAI,EAAE,IAAgB,GAAG;AAAA,QAChC,WAAW,OAAO,IAAI,GAAG,GAAG;AAC1B,eAAK,OAAO,IAAgB,GAAG;AAAA,QACjC,OAAO;AACL,eAAK,KAAK,cAAc,WAAW,SAAS,CAAC;AAC7C,iBAAO,IAAI,KAAK,EAAE;AAAA,QACpB;AAEA,eAAO;AAAA,MACT,CAAC;AACD,YAAM,KAAK;AAAA,IACb,UAAE;AACA,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,WAAW;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAe;AAAA,EAEf,MAAM,WAA0B;AAAA,EAAC;AAAA,EAEjC,OAAO,cAAuC;AAC5C,QAAI,CAAC,wBAAwB,UAAU;AACrC,8BAAwB,WAAW,IAAI,wBAAwB;AAAA,IACjE;AACA,WAAO,wBAAwB;AAAA,EACjC;AAAA,EAEA,cAAc,WAGC;AACb,QAAI,UAAU,aAAa,cAAc;AACvC,YAAM,OAAO,IAAI,qBAAqB,UAAU,MAAoB;AACpE,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,aAAa,UAAU;AACnC,YAAM,OAAO,IAAI,iBAAiB,UAAU,MAAsB;AAClE,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,MAAM,kCAAkC,UAAU,QAAQ,EAAE;AAAA,EACxE;AACF;","names":[]}
@@ -10,7 +10,7 @@ class GenerateApiDocsCommand extends Command {
10
10
  static {
11
11
  __name(this, "GenerateApiDocsCommand");
12
12
  }
13
- static paths = [[`generate`, `apidocsv2`]];
13
+ static paths = [[`generate`, `apidocs`]];
14
14
  static usage = Command.Usage({
15
15
  category: `Generate`,
16
16
  description: `Generate OpenAPI documentation from routes`,
@@ -50,14 +50,14 @@ api_docs: {
50
50
  examples: [
51
51
  [
52
52
  `Generate from routes`,
53
- `$0 generate apidocsv2 generate-from-routes --output path/to/output.json`
53
+ `$0 generate apidocs generate-from-routes --output path/to/output.json`
54
54
  ],
55
55
  [
56
56
  `Generate base spec`,
57
- `$0 generate apidocsv2 generate-base --output path/to/output.json`
57
+ `$0 generate apidocs generate-base --output path/to/output.json`
58
58
  ],
59
- [`Merge files`, `$0 generate apidocsv2 merge-files`],
60
- [`Show help`, `$0 generate apidocsv2 --help`]
59
+ [`Merge files`, `$0 generate apidocs merge-files`],
60
+ [`Show help`, `$0 generate apidocs --help`]
61
61
  ]
62
62
  });
63
63
  subcommand = Option.String({ required: false });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app/console/generate/GenerateApiDocsCommand.mts"],"sourcesContent":["/*\nhow this command should work:\n<command> generate-from-routes --output path/to/output.json\n<command> generate-base --output path/to/output.json\n<command> merge-files # file lists/details are in config\n<command> # will show help\n*/\nimport { cli, router } from \"../../../facades.mjs\";\nimport { Command, Option } from \"clipanion\";\nimport path from \"path\";\nimport * as fs from \"fs/promises\";\nimport { config } from \"../../../config.mjs\";\nimport { Arr } from \"@devbro/neko-helper\";\n\nexport class GenerateApiDocsCommand extends Command {\n static paths = [[`generate`, `apidocsv2`]];\n\n static usage = Command.Usage({\n category: `Generate`,\n description: `Generate OpenAPI documentation from routes`,\n details: `\n This command utility generates OpenAPI 3.0 specification documentation by analyzing\n your application's routes and merging with example files.\n \n Subcommands:\n - generate-from-routes: Generate OpenAPI spec from registered routes\n - generate-base: Generate base OpenAPI specification structure\n - merge-files: Merge multiple OpenAPI files into final documentation\n\n \n This command depends on config data. make sure your default config contains the following:\n\n\\`\\`\\`\napi_docs: {\n\n merge_files: [\n\n path.join(__dirname, '../..', 'private', 'openapi_base.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),\n\n ],\n\n output: path.join(__dirname, '../..', 'public', 'openapi.json'),\n\n}\n\n\\`\\`\\`\n `,\n examples: [\n [\n `Generate from routes`,\n `$0 generate apidocsv2 generate-from-routes --output path/to/output.json`,\n ],\n [\n `Generate base spec`,\n `$0 generate apidocsv2 generate-base --output path/to/output.json`,\n ],\n [`Merge files`, `$0 generate apidocsv2 merge-files`],\n [`Show help`, `$0 generate apidocsv2 --help`],\n ],\n });\n\n subcommand = Option.String({ required: false });\n\n output = Option.String(`--output,-o`, {\n description: `Output file path for generated documentation`,\n });\n\n config = Option.String(`--config,-c`, {\n description: `Path in config to get details from (default: api_docs)`,\n required: false,\n });\n\n async execute() {\n if (!this.subcommand) {\n this.context.stdout.write(\n this.constructor.usage?.toString() || \"No help available\\n\",\n );\n return 0;\n }\n\n switch (this.subcommand) {\n case \"generate-from-routes\":\n return await this.executeGenerateFromRoutes();\n case \"generate-base\":\n return await this.executeGenerateBase();\n case \"merge-files\":\n return await this.executeMergeFiles();\n default:\n this.context.stderr.write(`Unknown subcommand: ${this.subcommand}\\n`);\n this.context.stdout.write(\n this.constructor.usage?.toString() || \"No help available\\n\",\n );\n return 1;\n }\n }\n\n private async executeGenerateFromRoutes() {\n this.context.stdout.write(\n `Generating OpenAPI documentation from routes...\\n`,\n );\n\n const openApiSpec = this.generateFromRoutes();\n const outputPath =\n this.output ||\n path.join(config.get(\"private_path\"), \"openapi_from_routes.json\");\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(\n outputPath,\n JSON.stringify(openApiSpec, null, 2),\n \"utf-8\",\n );\n\n this.context.stdout.write(\n `OpenAPI routes documentation generated at: ${outputPath}\\n`,\n );\n this.context.stdout.write(\n `Total routes documented: ${Object.keys(openApiSpec.paths).length}\\n`,\n );\n return 0;\n }\n\n private async executeGenerateBase() {\n this.context.stdout.write(`Generating base OpenAPI specification...\\n`);\n\n const baseSpec = this.getBaseOpenApiSpec();\n const outputPath =\n this.output || path.join(config.get(\"private_path\"), \"openapi_base.json\");\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), \"utf-8\");\n\n this.context.stdout.write(\n `Base OpenAPI specification generated at: ${outputPath}\\n`,\n );\n return 0;\n }\n\n private async executeMergeFiles() {\n this.context.stdout.write(`Merging OpenAPI files...\\n`);\n let configPath = this.config || \"api_docs\";\n\n const files_to_merge: string[] = config.get(`${configPath}.merge_files`);\n let final_api_docs = {};\n\n for (const file_path of files_to_merge) {\n try {\n const file_json = JSON.parse(await fs.readFile(file_path, \"utf8\"));\n final_api_docs = Arr.deepMerge(final_api_docs, file_json);\n this.context.stdout.write(` Merged: ${file_path}\\n`);\n } catch (error) {\n this.context.stderr.write(\n ` Warning: Could not read ${file_path}: ${(error as Error).message}\\n`,\n );\n }\n }\n\n const outputPath = this.output || config.get(`${configPath}.output`);\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));\n\n this.context.stdout.write(\n `Final OpenAPI document written to: ${outputPath}\\n`,\n );\n return 0;\n }\n\n private extractParameters(routePath: string): any[] {\n const paramRegex = /:([a-zA-Z0-9_]+)/g;\n const parameters: any[] = [];\n let match;\n\n while ((match = paramRegex.exec(routePath)) !== null) {\n parameters.push({\n name: match[1],\n in: \"path\",\n required: true,\n schema: {\n type: \"string\",\n },\n description: `Path parameter ${match[1]}`,\n });\n }\n\n return parameters;\n }\n\n private generateFromRoutes() {\n const openApiSpec = {\n paths: {} as any,\n };\n const routes = router().routes;\n\n // Process each route\n for (const route of routes) {\n const routePath = route.path;\n // Convert route path to OpenAPI format (e.g., /api/:id -> /api/{id})\n const openApiPath = routePath.replace(/\\/$/g, \"\"); //.replace(/:([a-zA-Z0-9_]+)/g, \"{$1}\");\n\n if (!openApiSpec.paths[openApiPath]) {\n openApiSpec.paths[openApiPath] = {};\n }\n\n // Add each HTTP method for this route\n for (const method of route.methods) {\n const lowerMethod = method.toLowerCase();\n\n // Skip HEAD as it's usually auto-generated\n if (lowerMethod === \"head\") {\n continue;\n }\n\n openApiSpec.paths[openApiPath][lowerMethod] = {\n summary: `${routePath}`,\n description: `Endpoint for ${method} ${routePath}`,\n security: [],\n parameters: this.extractParameters(routePath),\n responses: {},\n };\n\n // Add request body for POST, PUT, PATCH\n if ([\"post\", \"put\", \"patch\"].includes(lowerMethod)) {\n openApiSpec.paths[openApiPath][lowerMethod].requestBody = {\n required: true,\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n },\n },\n },\n };\n }\n }\n }\n\n return openApiSpec;\n }\n\n getBaseOpenApiSpec() {\n // Generate OpenAPI 3.0 specification\n const openApiSpec = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n description: \"Auto-generated API documentation\",\n },\n servers: [\n {\n url: \"/\",\n description: \"Local server\",\n },\n ],\n components: {\n securitySchemes: {\n bearerAuth: {\n type: \"http\",\n scheme: \"bearer\",\n bearerFormat: \"JWT\",\n description: \"JWT token authentication\",\n },\n },\n },\n security: [\n {\n bearerAuth: [],\n },\n ],\n paths: {} as Record<string, any>,\n };\n\n return openApiSpec;\n }\n}\n\ncli().register(GenerateApiDocsCommand);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/app/console/generate/GenerateApiDocsCommand.mts"],"sourcesContent":["/*\nhow this command should work:\n<command> generate-from-routes --output path/to/output.json\n<command> generate-base --output path/to/output.json\n<command> merge-files # file lists/details are in config\n<command> # will show help\n*/\nimport { cli, router } from \"../../../facades.mjs\";\nimport { Command, Option } from \"clipanion\";\nimport path from \"path\";\nimport * as fs from \"fs/promises\";\nimport { config } from \"../../../config.mjs\";\nimport { Arr } from \"@devbro/neko-helper\";\n\nexport class GenerateApiDocsCommand extends Command {\n static paths = [[`generate`, `apidocs`]];\n\n static usage = Command.Usage({\n category: `Generate`,\n description: `Generate OpenAPI documentation from routes`,\n details: `\n This command utility generates OpenAPI 3.0 specification documentation by analyzing\n your application's routes and merging with example files.\n \n Subcommands:\n - generate-from-routes: Generate OpenAPI spec from registered routes\n - generate-base: Generate base OpenAPI specification structure\n - merge-files: Merge multiple OpenAPI files into final documentation\n\n \n This command depends on config data. make sure your default config contains the following:\n\n\\`\\`\\`\napi_docs: {\n\n merge_files: [\n\n path.join(__dirname, '../..', 'private', 'openapi_base.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_from_routes.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_from_tests.json'),\n\n path.join(__dirname, '../..', 'private', 'openapi_other_user_changes.json'),\n\n ],\n\n output: path.join(__dirname, '../..', 'public', 'openapi.json'),\n\n}\n\n\\`\\`\\`\n `,\n examples: [\n [\n `Generate from routes`,\n `$0 generate apidocs generate-from-routes --output path/to/output.json`,\n ],\n [\n `Generate base spec`,\n `$0 generate apidocs generate-base --output path/to/output.json`,\n ],\n [`Merge files`, `$0 generate apidocs merge-files`],\n [`Show help`, `$0 generate apidocs --help`],\n ],\n });\n\n subcommand = Option.String({ required: false });\n\n output = Option.String(`--output,-o`, {\n description: `Output file path for generated documentation`,\n });\n\n config = Option.String(`--config,-c`, {\n description: `Path in config to get details from (default: api_docs)`,\n required: false,\n });\n\n async execute() {\n if (!this.subcommand) {\n this.context.stdout.write(\n this.constructor.usage?.toString() || \"No help available\\n\",\n );\n return 0;\n }\n\n switch (this.subcommand) {\n case \"generate-from-routes\":\n return await this.executeGenerateFromRoutes();\n case \"generate-base\":\n return await this.executeGenerateBase();\n case \"merge-files\":\n return await this.executeMergeFiles();\n default:\n this.context.stderr.write(`Unknown subcommand: ${this.subcommand}\\n`);\n this.context.stdout.write(\n this.constructor.usage?.toString() || \"No help available\\n\",\n );\n return 1;\n }\n }\n\n private async executeGenerateFromRoutes() {\n this.context.stdout.write(\n `Generating OpenAPI documentation from routes...\\n`,\n );\n\n const openApiSpec = this.generateFromRoutes();\n const outputPath =\n this.output ||\n path.join(config.get(\"private_path\"), \"openapi_from_routes.json\");\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(\n outputPath,\n JSON.stringify(openApiSpec, null, 2),\n \"utf-8\",\n );\n\n this.context.stdout.write(\n `OpenAPI routes documentation generated at: ${outputPath}\\n`,\n );\n this.context.stdout.write(\n `Total routes documented: ${Object.keys(openApiSpec.paths).length}\\n`,\n );\n return 0;\n }\n\n private async executeGenerateBase() {\n this.context.stdout.write(`Generating base OpenAPI specification...\\n`);\n\n const baseSpec = this.getBaseOpenApiSpec();\n const outputPath =\n this.output || path.join(config.get(\"private_path\"), \"openapi_base.json\");\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), \"utf-8\");\n\n this.context.stdout.write(\n `Base OpenAPI specification generated at: ${outputPath}\\n`,\n );\n return 0;\n }\n\n private async executeMergeFiles() {\n this.context.stdout.write(`Merging OpenAPI files...\\n`);\n let configPath = this.config || \"api_docs\";\n\n const files_to_merge: string[] = config.get(`${configPath}.merge_files`);\n let final_api_docs = {};\n\n for (const file_path of files_to_merge) {\n try {\n const file_json = JSON.parse(await fs.readFile(file_path, \"utf8\"));\n final_api_docs = Arr.deepMerge(final_api_docs, file_json);\n this.context.stdout.write(` Merged: ${file_path}\\n`);\n } catch (error) {\n this.context.stderr.write(\n ` Warning: Could not read ${file_path}: ${(error as Error).message}\\n`,\n );\n }\n }\n\n const outputPath = this.output || config.get(`${configPath}.output`);\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n\n await fs.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));\n\n this.context.stdout.write(\n `Final OpenAPI document written to: ${outputPath}\\n`,\n );\n return 0;\n }\n\n private extractParameters(routePath: string): any[] {\n const paramRegex = /:([a-zA-Z0-9_]+)/g;\n const parameters: any[] = [];\n let match;\n\n while ((match = paramRegex.exec(routePath)) !== null) {\n parameters.push({\n name: match[1],\n in: \"path\",\n required: true,\n schema: {\n type: \"string\",\n },\n description: `Path parameter ${match[1]}`,\n });\n }\n\n return parameters;\n }\n\n private generateFromRoutes() {\n const openApiSpec = {\n paths: {} as any,\n };\n const routes = router().routes;\n\n // Process each route\n for (const route of routes) {\n const routePath = route.path;\n // Convert route path to OpenAPI format (e.g., /api/:id -> /api/{id})\n const openApiPath = routePath.replace(/\\/$/g, \"\"); //.replace(/:([a-zA-Z0-9_]+)/g, \"{$1}\");\n\n if (!openApiSpec.paths[openApiPath]) {\n openApiSpec.paths[openApiPath] = {};\n }\n\n // Add each HTTP method for this route\n for (const method of route.methods) {\n const lowerMethod = method.toLowerCase();\n\n // Skip HEAD as it's usually auto-generated\n if (lowerMethod === \"head\") {\n continue;\n }\n\n openApiSpec.paths[openApiPath][lowerMethod] = {\n summary: `${routePath}`,\n description: `Endpoint for ${method} ${routePath}`,\n security: [],\n parameters: this.extractParameters(routePath),\n responses: {},\n };\n\n // Add request body for POST, PUT, PATCH\n if ([\"post\", \"put\", \"patch\"].includes(lowerMethod)) {\n openApiSpec.paths[openApiPath][lowerMethod].requestBody = {\n required: true,\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n },\n },\n },\n };\n }\n }\n }\n\n return openApiSpec;\n }\n\n getBaseOpenApiSpec() {\n // Generate OpenAPI 3.0 specification\n const openApiSpec = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n description: \"Auto-generated API documentation\",\n },\n servers: [\n {\n url: \"/\",\n description: \"Local server\",\n },\n ],\n components: {\n securitySchemes: {\n bearerAuth: {\n type: \"http\",\n scheme: \"bearer\",\n bearerFormat: \"JWT\",\n description: \"JWT token authentication\",\n },\n },\n },\n security: [\n {\n bearerAuth: [],\n },\n ],\n paths: {} as Record<string, any>,\n };\n\n return openApiSpec;\n }\n}\n\ncli().register(GenerateApiDocsCommand);\n"],"mappings":"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","names":[]}
@@ -135,6 +135,10 @@ var DatabaseServiceProvider = class _DatabaseServiceProvider extends Middleware
135
135
  const conn = new import_neko_sql.PostgresqlConnection(db_config.config);
136
136
  return conn;
137
137
  }
138
+ if (db_config.provider === "sqlite") {
139
+ const conn = new import_neko_sql.SqliteConnection(db_config.config);
140
+ return conn;
141
+ }
138
142
  throw new Error(`Unsupported database provider: ${db_config.provider}`);
139
143
  }
140
144
  };
@@ -688,27 +688,58 @@ import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
688
688
  // src/facades.mts
689
689
  var import_neko_cache2 = require("@devbro/neko-cache");
690
690
  var import_neko_queue2 = require("@devbro/neko-queue");
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
+ }
715
+ });
716
+ }
717
+ __name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
691
718
  var router = (0, import_neko_helper3.createSingleton)(() => new Router());
692
- var scheduler = (0, import_neko_helper3.createSingleton)(() => {
693
- const rc = new import_neko_scheduler.Scheduler();
694
- rc.setErrorHandler((err, job) => {
695
- logger().error({
696
- msg: "Scheduled job error",
697
- err,
698
- job_name: job.getName()
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
+ });
699
728
  });
700
- });
701
- return rc;
702
- });
729
+ return rc;
730
+ })
731
+ );
703
732
  var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
704
- var storage = (0, import_neko_helper3.createSingleton)((label = "default") => {
705
- let storage_config = import_neko_config.config.get(["storages", label].join("."));
706
- const provider = import_neko_storage2.StorageProviderFactory.create(
707
- storage_config.provider,
708
- storage_config.config
709
- );
710
- return new import_neko_storage2.Storage(provider);
711
- });
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
+ );
712
743
  var cli = (0, import_neko_helper3.createSingleton)(() => {
713
744
  const [node, app, ...args] = process.argv;
714
745
  return new import_clipanion.Cli({
@@ -723,46 +754,54 @@ var httpServer = (0, import_neko_helper3.createSingleton)(() => {
723
754
  server.setRouter(router());
724
755
  return server;
725
756
  });
726
- var logger = (0, import_neko_helper3.createSingleton)((label) => {
727
- const logger_config = import_neko_config.config.get(["loggers", label].join("."));
728
- const rc = new import_neko_logger.Logger(logger_config);
729
- rc.setExtrasFunction((message) => {
730
- message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
731
- return message;
732
- });
733
- return rc;
734
- });
735
- var mailer = (0, import_neko_helper3.createSingleton)((label) => {
736
- const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
737
- const provider = import_neko_mailer2.MailerProviderFactory.create(
738
- mailer_config.provider,
739
- mailer_config.config
740
- );
741
- const rc = new import_neko_mailer2.Mailer(provider);
742
- return rc;
743
- });
744
- var queue = (0, import_neko_helper3.createSingleton)((label) => {
745
- const queue_config = import_neko_config.config.get(["queues", label].join("."));
746
- if (!queue_config) {
747
- throw new Error(`Queue configuration for '${label}' not found`);
748
- }
749
- const provider = import_neko_queue2.QueueTransportFactory.create(
750
- queue_config.provider,
751
- queue_config.config
752
- );
753
- return new import_neko_queue2.QueueConnection(provider);
754
- });
755
- var cache = (0, import_neko_helper3.createSingleton)((label) => {
756
- const cache_config = import_neko_config.config.get(["caches", label].join("."));
757
- if (!cache_config) {
758
- throw new Error(`Cache configuration for '${label}' not found`);
759
- }
760
- const provider = CacheProviderFactory.create(
761
- cache_config.provider,
762
- cache_config.config
763
- );
764
- return new import_neko_cache2.Cache(provider);
765
- });
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
+ );
766
805
 
767
806
  // src/app/console/DefaultCommand.mts
768
807
  var DefaultCommand = class extends import_clipanion2.Command {
@@ -691,27 +691,58 @@ import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
691
691
  // src/facades.mts
692
692
  var import_neko_cache2 = require("@devbro/neko-cache");
693
693
  var import_neko_queue2 = require("@devbro/neko-queue");
694
+ function wrapSingletonWithAccessors(singletonFn) {
695
+ let methodsInitialized = false;
696
+ const initializeMethods = /* @__PURE__ */ __name(() => {
697
+ if (methodsInitialized) return;
698
+ const defaultInstance = singletonFn();
699
+ const prototype = Object.getPrototypeOf(defaultInstance);
700
+ const methodNames = Object.getOwnPropertyNames(prototype).filter(
701
+ (name) => name !== "constructor" && typeof prototype[name] === "function"
702
+ );
703
+ for (const methodName of methodNames) {
704
+ singletonFn[methodName] = (...args) => {
705
+ const instance = singletonFn();
706
+ return instance[methodName](...args);
707
+ };
708
+ }
709
+ methodsInitialized = true;
710
+ }, "initializeMethods");
711
+ return new Proxy(singletonFn, {
712
+ get(target, prop, receiver) {
713
+ if (typeof prop === "string" && !Reflect.has(target, prop)) {
714
+ initializeMethods();
715
+ }
716
+ return Reflect.get(target, prop, receiver);
717
+ }
718
+ });
719
+ }
720
+ __name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
694
721
  var router = (0, import_neko_helper3.createSingleton)(() => new Router());
695
- var scheduler = (0, import_neko_helper3.createSingleton)(() => {
696
- const rc = new import_neko_scheduler.Scheduler();
697
- rc.setErrorHandler((err, job) => {
698
- logger().error({
699
- msg: "Scheduled job error",
700
- err,
701
- job_name: job.getName()
722
+ var scheduler = wrapSingletonWithAccessors(
723
+ (0, import_neko_helper3.createSingleton)(() => {
724
+ const rc = new import_neko_scheduler.Scheduler();
725
+ rc.setErrorHandler((err, job) => {
726
+ logger().error({
727
+ msg: "Scheduled job error",
728
+ err,
729
+ job_name: job.getName()
730
+ });
702
731
  });
703
- });
704
- return rc;
705
- });
732
+ return rc;
733
+ })
734
+ );
706
735
  var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
707
- var storage = (0, import_neko_helper3.createSingleton)((label = "default") => {
708
- let storage_config = import_neko_config.config.get(["storages", label].join("."));
709
- const provider = import_neko_storage2.StorageProviderFactory.create(
710
- storage_config.provider,
711
- storage_config.config
712
- );
713
- return new import_neko_storage2.Storage(provider);
714
- });
736
+ var storage = wrapSingletonWithAccessors(
737
+ (0, import_neko_helper3.createSingleton)((label = "default") => {
738
+ let storage_config = import_neko_config.config.get(["storages", label].join("."));
739
+ const provider = import_neko_storage2.StorageProviderFactory.create(
740
+ storage_config.provider,
741
+ storage_config.config
742
+ );
743
+ return new import_neko_storage2.Storage(provider);
744
+ })
745
+ );
715
746
  var cli = (0, import_neko_helper3.createSingleton)(() => {
716
747
  const [node, app, ...args] = process.argv;
717
748
  return new import_clipanion.Cli({
@@ -726,46 +757,54 @@ var httpServer = (0, import_neko_helper3.createSingleton)(() => {
726
757
  server.setRouter(router());
727
758
  return server;
728
759
  });
729
- var logger = (0, import_neko_helper3.createSingleton)((label) => {
730
- const logger_config = import_neko_config.config.get(["loggers", label].join("."));
731
- const rc = new import_neko_logger.Logger(logger_config);
732
- rc.setExtrasFunction((message) => {
733
- message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
734
- return message;
735
- });
736
- return rc;
737
- });
738
- var mailer = (0, import_neko_helper3.createSingleton)((label) => {
739
- const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
740
- const provider = import_neko_mailer2.MailerProviderFactory.create(
741
- mailer_config.provider,
742
- mailer_config.config
743
- );
744
- const rc = new import_neko_mailer2.Mailer(provider);
745
- return rc;
746
- });
747
- var queue = (0, import_neko_helper3.createSingleton)((label) => {
748
- const queue_config = import_neko_config.config.get(["queues", label].join("."));
749
- if (!queue_config) {
750
- throw new Error(`Queue configuration for '${label}' not found`);
751
- }
752
- const provider = import_neko_queue2.QueueTransportFactory.create(
753
- queue_config.provider,
754
- queue_config.config
755
- );
756
- return new import_neko_queue2.QueueConnection(provider);
757
- });
758
- var cache = (0, import_neko_helper3.createSingleton)((label) => {
759
- const cache_config = import_neko_config.config.get(["caches", label].join("."));
760
- if (!cache_config) {
761
- throw new Error(`Cache configuration for '${label}' not found`);
762
- }
763
- const provider = CacheProviderFactory.create(
764
- cache_config.provider,
765
- cache_config.config
766
- );
767
- return new import_neko_cache2.Cache(provider);
768
- });
760
+ var logger = wrapSingletonWithAccessors(
761
+ (0, import_neko_helper3.createSingleton)((label) => {
762
+ const logger_config = import_neko_config.config.get(["loggers", label].join("."));
763
+ const rc = new import_neko_logger.Logger(logger_config);
764
+ rc.setExtrasFunction((message) => {
765
+ message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
766
+ return message;
767
+ });
768
+ return rc;
769
+ })
770
+ );
771
+ var mailer = wrapSingletonWithAccessors(
772
+ (0, import_neko_helper3.createSingleton)((label) => {
773
+ const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
774
+ const provider = import_neko_mailer2.MailerProviderFactory.create(
775
+ mailer_config.provider,
776
+ mailer_config.config
777
+ );
778
+ const rc = new import_neko_mailer2.Mailer(provider);
779
+ return rc;
780
+ })
781
+ );
782
+ var queue = wrapSingletonWithAccessors(
783
+ (0, import_neko_helper3.createSingleton)((label) => {
784
+ const queue_config = import_neko_config.config.get(["queues", label].join("."));
785
+ if (!queue_config) {
786
+ throw new Error(`Queue configuration for '${label}' not found`);
787
+ }
788
+ const provider = import_neko_queue2.QueueTransportFactory.create(
789
+ queue_config.provider,
790
+ queue_config.config
791
+ );
792
+ return new import_neko_queue2.QueueConnection(provider);
793
+ })
794
+ );
795
+ var cache = wrapSingletonWithAccessors(
796
+ (0, import_neko_helper3.createSingleton)((label) => {
797
+ const cache_config = import_neko_config.config.get(["caches", label].join("."));
798
+ if (!cache_config) {
799
+ throw new Error(`Cache configuration for '${label}' not found`);
800
+ }
801
+ const provider = CacheProviderFactory.create(
802
+ cache_config.provider,
803
+ cache_config.config
804
+ );
805
+ return new import_neko_cache2.Cache(provider);
806
+ })
807
+ );
769
808
 
770
809
  // src/app/console/KeyGenerateCommand.mts
771
810
  var KeyGenerateCommand = class extends import_clipanion2.Command {