@honestjs/rpc-plugin 1.1.0 → 1.2.0

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/README.md CHANGED
@@ -1,14 +1,7 @@
1
- # @honestjs/rpc-plugin
1
+ # RPC Plugin
2
2
 
3
- A comprehensive RPC plugin for HonestJS that combines route analysis, schema generation, and client generation into a
4
- single solution.
5
-
6
- ## Features
7
-
8
- - **Route Analysis**: Automatically analyzes controller methods and extracts type information using ts-morph
9
- - **Schema Generation**: Generates JSON schemas and TypeScript interfaces from types used in controllers
10
- - **Client Generation**: Creates a fully-typed TypeScript RPC client with proper parameter typing
11
- - **Type Safety**: Full TypeScript support with generated types and interfaces
3
+ The RPC Plugin automatically analyzes your HonestJS controllers and generates a fully-typed TypeScript RPC client with
4
+ proper parameter typing.
12
5
 
13
6
  ## Installation
14
7
 
@@ -20,24 +13,18 @@ yarn add @honestjs/rpc-plugin
20
13
  pnpm add @honestjs/rpc-plugin
21
14
  ```
22
15
 
23
- ## Usage
24
-
25
- ### Basic Setup
16
+ ## Basic Setup
26
17
 
27
18
  ```typescript
28
19
  import { RPCPlugin } from '@honestjs/rpc-plugin'
29
20
  import { Application } from 'honestjs'
30
21
 
31
22
  const app = new Application({
32
- plugins: [
33
- new RPCPlugin({
34
- outputDir: './generated/rpc'
35
- })
36
- ]
23
+ plugins: [RPCPlugin]
37
24
  })
38
25
  ```
39
26
 
40
- ### Configuration Options
27
+ ## Configuration Options
41
28
 
42
29
  ```typescript
43
30
  interface RPCPluginOptions {
@@ -87,24 +74,13 @@ apiClient.setDefaultHeaders({
87
74
  'X-API-Key': 'your-api-key',
88
75
  Authorization: 'Bearer your-jwt-token'
89
76
  })
90
-
91
- // Use with custom fetch function (e.g., for testing or custom logic)
92
- const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {
93
- console.log('Making request to:', input)
94
- return fetch(input, init)
95
- }
96
-
97
- const apiClientWithCustomFetch = new ApiClient('http://localhost:3000', {
98
- fetchFn: customFetch,
99
- defaultHeaders: { 'X-Custom-Header': 'value' }
100
- })
101
77
  ```
102
78
 
103
79
  The generated `client.ts` file contains everything you need:
104
80
 
105
81
  - **ApiClient class** with all your controller methods
106
82
  - **Type definitions** for requests, responses, and DTOs
107
- - **Utility types** like RequestOptions and ApiResponse
83
+ - **Utility types** like RequestOptions
108
84
  - **Generated interfaces** from your controller types
109
85
 
110
86
  ## Custom Fetch Functions
@@ -220,14 +196,6 @@ expect(mockFetch).toHaveBeenCalledWith('http://test.com/api/v1/users/123', expec
220
196
  - Creates parameter validation and typing
221
197
  - Builds the complete RPC client with proper error handling
222
198
 
223
- ## Benefits of the Unified Approach
224
-
225
- - **No Duplication**: Single source of truth for all type information
226
- - **Tight Coupling**: Components share data directly without file I/O
227
- - **Better Performance**: Eliminates redundant analysis and file generation
228
- - **Consistent Types**: All generated code uses the same type definitions
229
- - **Easier Maintenance**: Single plugin to configure and maintain
230
-
231
199
  ## Example Generated Output
232
200
 
233
201
  ### Generated Client
@@ -236,15 +204,20 @@ expect(mockFetch).toHaveBeenCalledWith('http://test.com/api/v1/users/123', expec
236
204
  export class ApiClient {
237
205
  get users() {
238
206
  return {
239
- create: async (
207
+ create: async <Result = User>(
240
208
  options: RequestOptions<{ name: string; email: string }, undefined, undefined, undefined>
241
- ): Promise<ApiResponse<any>> => {
242
- return this.request('POST', `/api/v1/users/`, options)
209
+ ) => {
210
+ return this.request<Result>('POST', `/api/v1/users/`, options)
243
211
  },
244
- list: async (
212
+ list: async <Result = User[]>(
245
213
  options?: RequestOptions<undefined, { page: number; limit: number }, undefined, undefined>
246
- ): Promise<ApiResponse<any>> => {
247
- return this.request('GET', `/api/v1/users/`, options)
214
+ ) => {
215
+ return this.request<Result>('GET', `/api/v1/users/`, options)
216
+ },
217
+ getById: async <Result = User>(
218
+ options: RequestOptions<undefined, { id: string }, undefined, undefined>
219
+ ) => {
220
+ return this.request<Result>('GET', `/api/v1/users/:id`, options)
248
221
  }
249
222
  }
250
223
  }
@@ -272,12 +245,100 @@ const rpcPlugin = new RPCPlugin()
272
245
  await rpcPlugin.analyze() // Manually trigger analysis and generation
273
246
  ```
274
247
 
275
- ## Dependencies
248
+ ## Advanced Usage
276
249
 
277
- - **ts-morph**: TypeScript source code analysis
278
- - **ts-json-schema-generator**: JSON schema generation from TypeScript types
279
- - **honestjs**: Core framework integration
250
+ ### Custom Controller Pattern
280
251
 
281
- ## License
252
+ If your controllers follow a different file structure:
253
+
254
+ ```typescript
255
+ new RPCPlugin({
256
+ controllerPattern: 'src/controllers/**/*.controller.ts',
257
+ outputDir: './src/generated/api'
258
+ })
259
+ ```
260
+
261
+ ### Manual Generation Control
262
+
263
+ Disable automatic generation and control when files are generated:
264
+
265
+ ```typescript
266
+ const rpcPlugin = new RPCPlugin({
267
+ generateOnInit: false
268
+ })
269
+
270
+ // Later in your code
271
+ await rpcPlugin.analyze()
272
+ ```
273
+
274
+ ## Integration with HonestJS
275
+
276
+ ### Controller Example
277
+
278
+ Here's how your controllers should be structured for optimal RPC generation:
279
+
280
+ ```typescript
281
+ import { Controller, Post, Get, Body, Param, Query } from 'honestjs'
282
282
 
283
- MIT
283
+ interface CreateUserDto {
284
+ name: string
285
+ email: string
286
+ }
287
+
288
+ interface ListUsersQuery {
289
+ page?: number
290
+ limit?: number
291
+ }
292
+
293
+ @Controller('/users')
294
+ export class UsersController {
295
+ @Post('/')
296
+ async create(@Body() createUserDto: CreateUserDto): Promise<User> {
297
+ // Implementation
298
+ }
299
+
300
+ @Get('/')
301
+ async list(@Query() query: ListUsersQuery): Promise<User[]> {
302
+ // Implementation
303
+ }
304
+
305
+ @Get('/:id')
306
+ async getById(@Param('id') id: string): Promise<User> {
307
+ // Implementation
308
+ }
309
+ }
310
+ ```
311
+
312
+ ### Module Registration
313
+
314
+ Ensure your controllers are properly registered in modules:
315
+
316
+ ```typescript
317
+ import { Module } from 'honestjs'
318
+ import { UsersController } from './users.controller'
319
+ import { UsersService } from './users.service'
320
+
321
+ @Module({
322
+ controllers: [UsersController],
323
+ providers: [UsersService]
324
+ })
325
+ export class UsersModule {}
326
+ ```
327
+
328
+ ## Error Handling
329
+
330
+ The generated client includes comprehensive error handling:
331
+
332
+ ```typescript
333
+ try {
334
+ const user = await apiClient.users.create({
335
+ body: { name: 'John', email: 'john@example.com' }
336
+ })
337
+ } catch (error) {
338
+ if (error instanceof ApiError) {
339
+ console.error(`API Error ${error.statusCode}: ${error.message}`)
340
+ } else {
341
+ console.error('Unexpected error:', error)
342
+ }
343
+ }
344
+ ```
package/dist/index.d.mts CHANGED
@@ -70,14 +70,6 @@ type RequestOptions<TParams = never, TQuery = never, TBody = never, THeaders = n
70
70
  * Custom fetch function type that matches the standard fetch API
71
71
  */
72
72
  type FetchFunction = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
73
- /**
74
- * API Response wrapper
75
- */
76
- interface ApiResponse<T = any> {
77
- data: T;
78
- message?: string;
79
- success: boolean;
80
- }
81
73
  /**
82
74
  * API Error class
83
75
  */
@@ -334,4 +326,4 @@ declare const BUILTIN_TYPES: Set<string>;
334
326
  */
335
327
  declare const GENERIC_TYPES: Set<string>;
336
328
 
337
- export { ApiError, type ApiResponse, BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, ClientGeneratorService, type ControllerGroups, DEFAULT_OPTIONS, type ExtendedRouteInfo, type FetchFunction, GENERIC_TYPES, type GeneratedClientInfo, LOG_PREFIX, type ParameterMetadataWithType, RPCPlugin, type RPCPluginOptions, type RequestOptions, RouteAnalyzerService, type RouteParameter, SchemaGeneratorService, type SchemaInfo, buildFullApiPath, buildFullPath, camelCase, extractNamedType, generateTypeImports, generateTypeScriptInterface, mapJsonSchemaTypeToTypeScript, safeToString };
329
+ export { ApiError, BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, ClientGeneratorService, type ControllerGroups, DEFAULT_OPTIONS, type ExtendedRouteInfo, type FetchFunction, GENERIC_TYPES, type GeneratedClientInfo, LOG_PREFIX, type ParameterMetadataWithType, RPCPlugin, type RPCPluginOptions, type RequestOptions, RouteAnalyzerService, type RouteParameter, SchemaGeneratorService, type SchemaInfo, buildFullApiPath, buildFullPath, camelCase, extractNamedType, generateTypeImports, generateTypeScriptInterface, mapJsonSchemaTypeToTypeScript, safeToString };
package/dist/index.d.ts CHANGED
@@ -70,14 +70,6 @@ type RequestOptions<TParams = never, TQuery = never, TBody = never, THeaders = n
70
70
  * Custom fetch function type that matches the standard fetch API
71
71
  */
72
72
  type FetchFunction = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
73
- /**
74
- * API Response wrapper
75
- */
76
- interface ApiResponse<T = any> {
77
- data: T;
78
- message?: string;
79
- success: boolean;
80
- }
81
73
  /**
82
74
  * API Error class
83
75
  */
@@ -334,4 +326,4 @@ declare const BUILTIN_TYPES: Set<string>;
334
326
  */
335
327
  declare const GENERIC_TYPES: Set<string>;
336
328
 
337
- export { ApiError, type ApiResponse, BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, ClientGeneratorService, type ControllerGroups, DEFAULT_OPTIONS, type ExtendedRouteInfo, type FetchFunction, GENERIC_TYPES, type GeneratedClientInfo, LOG_PREFIX, type ParameterMetadataWithType, RPCPlugin, type RPCPluginOptions, type RequestOptions, RouteAnalyzerService, type RouteParameter, SchemaGeneratorService, type SchemaInfo, buildFullApiPath, buildFullPath, camelCase, extractNamedType, generateTypeImports, generateTypeScriptInterface, mapJsonSchemaTypeToTypeScript, safeToString };
329
+ export { ApiError, BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, ClientGeneratorService, type ControllerGroups, DEFAULT_OPTIONS, type ExtendedRouteInfo, type FetchFunction, GENERIC_TYPES, type GeneratedClientInfo, LOG_PREFIX, type ParameterMetadataWithType, RPCPlugin, type RPCPluginOptions, type RequestOptions, RouteAnalyzerService, type RouteParameter, SchemaGeneratorService, type SchemaInfo, buildFullApiPath, buildFullPath, camelCase, extractNamedType, generateTypeImports, generateTypeScriptInterface, mapJsonSchemaTypeToTypeScript, safeToString };
package/dist/index.js CHANGED
@@ -162,15 +162,6 @@ var ClientGeneratorService = class {
162
162
  // TYPES SECTION
163
163
  // ============================================================================
164
164
 
165
- /**
166
- * API Response wrapper
167
- */
168
- export interface ApiResponse<T = any> {
169
- data: T
170
- message?: string
171
- success: boolean
172
- }
173
-
174
165
  /**
175
166
  * API Error class
176
167
  */
@@ -283,7 +274,7 @@ export class ApiClient {
283
274
  method: string,
284
275
  path: string,
285
276
  options: RequestOptions<any, any, any, any> = {}
286
- ): Promise<ApiResponse<T>> {
277
+ ): Promise<T> {
287
278
  const { params, query, body, headers = {} } = options as any
288
279
 
289
280
  // Build the final URL with path parameters
@@ -356,8 +347,9 @@ ${this.generateControllerMethods(controllerGroups)}
356
347
  const methodName = camelCase(safeToString(route.handler));
357
348
  const httpMethod = safeToString(route.method).toLowerCase();
358
349
  const { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route);
350
+ const returnType = this.extractReturnType(route.returns);
359
351
  const hasRequiredParams = pathParams.length > 0 || queryParams.some((p) => p.required) || bodyParams.length > 0 && httpMethod !== "get";
360
- methods += ` ${methodName}: async (options${hasRequiredParams ? "" : "?"}: RequestOptions<`;
352
+ methods += ` ${methodName}: async <Result = ${returnType}>(options${hasRequiredParams ? "" : "?"}: RequestOptions<`;
361
353
  if (pathParams.length > 0) {
362
354
  const pathParamTypes = pathParams.map((p) => {
363
355
  const paramName = p.name;
@@ -391,8 +383,7 @@ ${this.generateControllerMethods(controllerGroups)}
391
383
  }
392
384
  methods += ", ";
393
385
  methods += "undefined";
394
- const returnType = this.extractReturnType(route.returns);
395
- methods += `>): Promise<ApiResponse<${returnType}>> => {
386
+ methods += `>) => {
396
387
  `;
397
388
  let requestPath = buildFullApiPath(route);
398
389
  if (pathParams.length > 0) {
@@ -402,7 +393,7 @@ ${this.generateControllerMethods(controllerGroups)}
402
393
  requestPath = requestPath.replace(placeholder, `:${paramName}`);
403
394
  }
404
395
  }
405
- methods += ` return this.request<${returnType}>('${httpMethod.toUpperCase()}', \`${requestPath}\`, options)
396
+ methods += ` return this.request<Result>('${httpMethod.toUpperCase()}', \`${requestPath}\`, options)
406
397
  `;
407
398
  methods += ` },
408
399
  `;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["// Main plugin export\nexport { RPCPlugin } from './rpc.plugin'\n\n// Export all types\nexport type {\n\tApiError,\n\tApiResponse,\n\tControllerGroups,\n\tExtendedRouteInfo,\n\tFetchFunction,\n\tGeneratedClientInfo,\n\tParameterMetadataWithType,\n\tRequestOptions,\n\tRouteParameter,\n\tRPCPluginOptions,\n\tSchemaInfo\n} from './types'\n\n// Export services for advanced usage\nexport { ClientGeneratorService } from './services/client-generator.service'\nexport { RouteAnalyzerService } from './services/route-analyzer.service'\nexport { SchemaGeneratorService } from './services/schema-generator.service'\n\n// Export utilities for custom implementations\nexport * from './utils/path-utils'\nexport * from './utils/schema-utils'\nexport * from './utils/string-utils'\nexport * from './utils/type-utils'\n\n// Export constants\nexport * from './constants/defaults'\n","import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n/**\n * Custom fetch function type that matches the standard fetch API\n */\nexport type FetchFunction = (\n\tinput: RequestInfo | URL,\n\tinit?: RequestInit\n) => Promise<Response>\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \n * // Use with custom fetch function (e.g., for testing or custom logic)\n * const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {\n * console.log('Making request to:', input)\n * return fetch(input, init)\n * }\n * \n * const apiClientWithCustomFetch = new ApiClient('http://localhost:3000', {\n * fetchFn: customFetch,\n * defaultHeaders: { 'X-Custom-Header': 'value' }\n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\tprivate fetchFn: FetchFunction\n\n\tconstructor(\n\t\tbaseUrl: string, \n\t\toptions: {\n\t\t\tdefaultHeaders?: Record<string, string>\n\t\t\tfetchFn?: FetchFunction\n\t\t} = {}\n\t) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...options.defaultHeaders\n\t\t}\n\t\tthis.fetchFn = options.fetchFn || fetch\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.fetchFn(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["import_path","path","fs","path","import_ts_morph","type","path","fs"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["// Main plugin export\nexport { RPCPlugin } from './rpc.plugin'\n\n// Export all types\nexport type {\n\tApiError,\n\tControllerGroups,\n\tExtendedRouteInfo,\n\tFetchFunction,\n\tGeneratedClientInfo,\n\tParameterMetadataWithType,\n\tRequestOptions,\n\tRouteParameter,\n\tRPCPluginOptions,\n\tSchemaInfo\n} from './types'\n\n// Export services for advanced usage\nexport { ClientGeneratorService } from './services/client-generator.service'\nexport { RouteAnalyzerService } from './services/route-analyzer.service'\nexport { SchemaGeneratorService } from './services/schema-generator.service'\n\n// Export utilities for custom implementations\nexport * from './utils/path-utils'\nexport * from './utils/schema-utils'\nexport * from './utils/string-utils'\nexport * from './utils/type-utils'\n\n// Export constants\nexport * from './constants/defaults'\n","import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n/**\n * Custom fetch function type that matches the standard fetch API\n */\nexport type FetchFunction = (\n\tinput: RequestInfo | URL,\n\tinit?: RequestInit\n) => Promise<Response>\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \n * // Use with custom fetch function (e.g., for testing or custom logic)\n * const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {\n * console.log('Making request to:', input)\n * return fetch(input, init)\n * }\n * \n * const apiClientWithCustomFetch = new ApiClient('http://localhost:3000', {\n * fetchFn: customFetch,\n * defaultHeaders: { 'X-Custom-Header': 'value' }\n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\tprivate fetchFn: FetchFunction\n\n\tconstructor(\n\t\tbaseUrl: string, \n\t\toptions: {\n\t\t\tdefaultHeaders?: Record<string, string>\n\t\t\tfetchFn?: FetchFunction\n\t\t} = {}\n\t) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...options.defaultHeaders\n\t\t}\n\t\tthis.fetchFn = options.fetchFn || fetch\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<T> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.fetchFn(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async <Result = ${returnType}>(options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\tmethods += `>) => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<Result>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["import_path","path","fs","path","import_ts_morph","type","path","fs"]}
package/dist/index.mjs CHANGED
@@ -110,15 +110,6 @@ var ClientGeneratorService = class {
110
110
  // TYPES SECTION
111
111
  // ============================================================================
112
112
 
113
- /**
114
- * API Response wrapper
115
- */
116
- export interface ApiResponse<T = any> {
117
- data: T
118
- message?: string
119
- success: boolean
120
- }
121
-
122
113
  /**
123
114
  * API Error class
124
115
  */
@@ -231,7 +222,7 @@ export class ApiClient {
231
222
  method: string,
232
223
  path: string,
233
224
  options: RequestOptions<any, any, any, any> = {}
234
- ): Promise<ApiResponse<T>> {
225
+ ): Promise<T> {
235
226
  const { params, query, body, headers = {} } = options as any
236
227
 
237
228
  // Build the final URL with path parameters
@@ -304,8 +295,9 @@ ${this.generateControllerMethods(controllerGroups)}
304
295
  const methodName = camelCase(safeToString(route.handler));
305
296
  const httpMethod = safeToString(route.method).toLowerCase();
306
297
  const { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route);
298
+ const returnType = this.extractReturnType(route.returns);
307
299
  const hasRequiredParams = pathParams.length > 0 || queryParams.some((p) => p.required) || bodyParams.length > 0 && httpMethod !== "get";
308
- methods += ` ${methodName}: async (options${hasRequiredParams ? "" : "?"}: RequestOptions<`;
300
+ methods += ` ${methodName}: async <Result = ${returnType}>(options${hasRequiredParams ? "" : "?"}: RequestOptions<`;
309
301
  if (pathParams.length > 0) {
310
302
  const pathParamTypes = pathParams.map((p) => {
311
303
  const paramName = p.name;
@@ -339,8 +331,7 @@ ${this.generateControllerMethods(controllerGroups)}
339
331
  }
340
332
  methods += ", ";
341
333
  methods += "undefined";
342
- const returnType = this.extractReturnType(route.returns);
343
- methods += `>): Promise<ApiResponse<${returnType}>> => {
334
+ methods += `>) => {
344
335
  `;
345
336
  let requestPath = buildFullApiPath(route);
346
337
  if (pathParams.length > 0) {
@@ -350,7 +341,7 @@ ${this.generateControllerMethods(controllerGroups)}
350
341
  requestPath = requestPath.replace(placeholder, `:${paramName}`);
351
342
  }
352
343
  }
353
- methods += ` return this.request<${returnType}>('${httpMethod.toUpperCase()}', \`${requestPath}\`, options)
344
+ methods += ` return this.request<Result>('${httpMethod.toUpperCase()}', \`${requestPath}\`, options)
354
345
  `;
355
346
  methods += ` },
356
347
  `;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n/**\n * Custom fetch function type that matches the standard fetch API\n */\nexport type FetchFunction = (\n\tinput: RequestInfo | URL,\n\tinit?: RequestInit\n) => Promise<Response>\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \n * // Use with custom fetch function (e.g., for testing or custom logic)\n * const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {\n * console.log('Making request to:', input)\n * return fetch(input, init)\n * }\n * \n * const apiClientWithCustomFetch = new ApiClient('http://localhost:3000', {\n * fetchFn: customFetch,\n * defaultHeaders: { 'X-Custom-Header': 'value' }\n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\tprivate fetchFn: FetchFunction\n\n\tconstructor(\n\t\tbaseUrl: string, \n\t\toptions: {\n\t\t\tdefaultHeaders?: Record<string, string>\n\t\t\tfetchFn?: FetchFunction\n\t\t} = {}\n\t) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...options.defaultHeaders\n\t\t}\n\t\tthis.fetchFn = options.fetchFn || fetch\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.fetchFn(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["fs","path","path","Project","Project","type","path","fs"]}
1
+ {"version":3,"sources":["../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n/**\n * Custom fetch function type that matches the standard fetch API\n */\nexport type FetchFunction = (\n\tinput: RequestInfo | URL,\n\tinit?: RequestInit\n) => Promise<Response>\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \n * // Use with custom fetch function (e.g., for testing or custom logic)\n * const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {\n * console.log('Making request to:', input)\n * return fetch(input, init)\n * }\n * \n * const apiClientWithCustomFetch = new ApiClient('http://localhost:3000', {\n * fetchFn: customFetch,\n * defaultHeaders: { 'X-Custom-Header': 'value' }\n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\tprivate fetchFn: FetchFunction\n\n\tconstructor(\n\t\tbaseUrl: string, \n\t\toptions: {\n\t\t\tdefaultHeaders?: Record<string, string>\n\t\t\tfetchFn?: FetchFunction\n\t\t} = {}\n\t) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...options.defaultHeaders\n\t\t}\n\t\tthis.fetchFn = options.fetchFn || fetch\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<T> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.fetchFn(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async <Result = ${returnType}>(options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\tmethods += `>) => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<Result>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["fs","path","path","Project","Project","type","path","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@honestjs/rpc-plugin",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "RPC plugin for HonestJS framework",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -29,12 +29,12 @@
29
29
  "directory": "packages/rpc-plugin"
30
30
  },
31
31
  "dependencies": {
32
- "ts-json-schema-generator": "^2.4.0",
32
+ "ts-json-schema-generator": "^2.5.0",
33
33
  "ts-morph": "^26.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "honestjs": "^0.1.5",
37
- "hono": "^4.9.4"
36
+ "honestjs": "^0.1.6",
37
+ "hono": "^4.12.3"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "honestjs": "^0.1.0",