@hodfords/nestjs-grpc-helper 11.5.0 → 12.0.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.
Files changed (162) hide show
  1. package/README.md +403 -118
  2. package/clients/custom-grpc.client.d.ts +1 -1
  3. package/clients/custom-grpc.client.js +37 -36
  4. package/clients/custom-grpc.client.js.map +1 -1
  5. package/commands/generate-proto.command.js +11 -12
  6. package/commands/generate-proto.command.js.map +1 -1
  7. package/commands/generate-sdk.command.js +11 -12
  8. package/commands/generate-sdk.command.js.map +1 -1
  9. package/commands/update-ai-skill.command.d.ts +6 -0
  10. package/commands/update-ai-skill.command.js +78 -0
  11. package/commands/update-ai-skill.command.js.map +1 -0
  12. package/constants/metadata-key.const.d.ts +7 -0
  13. package/constants/metadata-key.const.js +8 -0
  14. package/constants/metadata-key.const.js.map +1 -0
  15. package/decorators/any-type.decorator.js +3 -6
  16. package/decorators/any-type.decorator.js.map +1 -1
  17. package/decorators/extend-type.decorator.js +8 -11
  18. package/decorators/extend-type.decorator.js.map +1 -1
  19. package/decorators/grpc-metadata.decorator.d.ts +3 -0
  20. package/decorators/grpc-metadata.decorator.js +24 -0
  21. package/decorators/grpc-metadata.decorator.js.map +1 -0
  22. package/decorators/grpc-param.decorator.d.ts +15 -0
  23. package/decorators/grpc-param.decorator.js +90 -0
  24. package/decorators/grpc-param.decorator.js.map +1 -0
  25. package/decorators/grpc-value.decorator.js +3 -7
  26. package/decorators/grpc-value.decorator.js.map +1 -1
  27. package/decorators/microservice.decorator.js +29 -19
  28. package/decorators/microservice.decorator.js.map +1 -1
  29. package/decorators/mock.decorator.d.ts +2 -1
  30. package/decorators/mock.decorator.js +16 -16
  31. package/decorators/mock.decorator.js.map +1 -1
  32. package/decorators/property.decorator.d.ts +1 -1
  33. package/decorators/property.decorator.js +10 -10
  34. package/decorators/property.decorator.js.map +1 -1
  35. package/decorators/sdk-expose.decorator.d.ts +3 -0
  36. package/decorators/sdk-expose.decorator.js +8 -0
  37. package/decorators/sdk-expose.decorator.js.map +1 -0
  38. package/documents/grpc-test.dto.d.ts +1 -0
  39. package/documents/grpc-test.dto.js +25 -19
  40. package/documents/grpc-test.dto.js.map +1 -1
  41. package/documents/microservice-document.controller.d.ts +3 -3
  42. package/documents/microservice-document.controller.js +27 -18
  43. package/documents/microservice-document.controller.js.map +1 -1
  44. package/documents/microservice-document.module.d.ts +1 -1
  45. package/documents/microservice-document.module.js +20 -22
  46. package/documents/microservice-document.module.js.map +1 -1
  47. package/dto/pagination.dto.d.ts +4 -0
  48. package/dto/pagination.dto.js +28 -0
  49. package/dto/pagination.dto.js.map +1 -0
  50. package/dto/sort.dto.d.ts +4 -0
  51. package/dto/sort.dto.js +30 -0
  52. package/dto/sort.dto.js.map +1 -0
  53. package/helpers/api-property.helper.d.ts +1 -1
  54. package/helpers/api-property.helper.js +3 -6
  55. package/helpers/api-property.helper.js.map +1 -1
  56. package/helpers/flat-param.helper.d.ts +7 -0
  57. package/helpers/flat-param.helper.js +83 -0
  58. package/helpers/flat-param.helper.js.map +1 -0
  59. package/helpers/generate.helper.d.ts +2 -2
  60. package/helpers/generate.helper.js +9 -14
  61. package/helpers/generate.helper.js.map +1 -1
  62. package/helpers/grpc-method.helper.d.ts +7 -0
  63. package/helpers/grpc-method.helper.js +37 -0
  64. package/helpers/grpc-method.helper.js.map +1 -0
  65. package/helpers/metadata-param.helper.d.ts +1 -0
  66. package/helpers/metadata-param.helper.js +29 -0
  67. package/helpers/metadata-param.helper.js.map +1 -0
  68. package/helpers/mock.helper.d.ts +2 -2
  69. package/helpers/mock.helper.js +30 -18
  70. package/helpers/mock.helper.js.map +1 -1
  71. package/helpers/property.helper.d.ts +8 -3
  72. package/helpers/property.helper.js +63 -27
  73. package/helpers/property.helper.js.map +1 -1
  74. package/helpers/proto-type.helper.d.ts +1 -1
  75. package/helpers/proto-type.helper.js +11 -12
  76. package/helpers/proto-type.helper.js.map +1 -1
  77. package/helpers/shell.helper.js +4 -6
  78. package/helpers/shell.helper.js.map +1 -1
  79. package/helpers/type.helper.js +1 -4
  80. package/helpers/type.helper.js.map +1 -1
  81. package/index.d.ts +23 -20
  82. package/index.js +23 -36
  83. package/index.js.map +1 -1
  84. package/interceptors/grpc-translation.interceptor.js +7 -10
  85. package/interceptors/grpc-translation.interceptor.js.map +1 -1
  86. package/package.json +115 -113
  87. package/responses/native.response.js +18 -24
  88. package/responses/native.response.js.map +1 -1
  89. package/sdk-config.json +21 -0
  90. package/sdk-stub/helpers/grpc.helper.d.ts +3 -1
  91. package/sdk-stub/helpers/grpc.helper.js +37 -22
  92. package/sdk-stub/helpers/grpc.helper.js.map +1 -1
  93. package/sdk-stub/helpers/grpc.helper.spec.ts +237 -0
  94. package/sdk-stub/helpers/grpc.helper.ts +25 -9
  95. package/sdk-stub/types/microservice-option.type.d.ts +3 -1
  96. package/sdk-stub/types/microservice-option.type.js +1 -2
  97. package/sdk-stub/types/microservice-option.type.ts +3 -1
  98. package/services/generate-document.service.d.ts +2 -2
  99. package/services/generate-document.service.js +46 -47
  100. package/services/generate-document.service.js.map +1 -1
  101. package/services/generate-microservice.service.d.ts +2 -4
  102. package/services/generate-microservice.service.js +88 -125
  103. package/services/generate-microservice.service.js.map +1 -1
  104. package/services/generate-proto.service.d.ts +4 -2
  105. package/services/generate-proto.service.js +39 -61
  106. package/services/generate-proto.service.js.map +1 -1
  107. package/services/generate-skill.service.d.ts +11 -0
  108. package/services/generate-skill.service.js +137 -0
  109. package/services/generate-skill.service.js.map +1 -0
  110. package/services/hbs-generator.service.d.ts +1 -0
  111. package/services/hbs-generator.service.js +20 -41
  112. package/services/hbs-generator.service.js.map +1 -1
  113. package/services/method-template.service.d.ts +5 -3
  114. package/services/method-template.service.js +28 -9
  115. package/services/method-template.service.js.map +1 -1
  116. package/services/mock-method-template.service.d.ts +5 -3
  117. package/services/mock-method-template.service.js +19 -22
  118. package/services/mock-method-template.service.js.map +1 -1
  119. package/services/mock-module-template.service.d.ts +1 -1
  120. package/services/mock-module-template.service.js +6 -8
  121. package/services/mock-module-template.service.js.map +1 -1
  122. package/services/module-template.service.d.ts +1 -1
  123. package/services/module-template.service.js +6 -8
  124. package/services/module-template.service.js.map +1 -1
  125. package/services/service-template.service.d.ts +2 -2
  126. package/services/service-template.service.js +8 -11
  127. package/services/service-template.service.js.map +1 -1
  128. package/storages/microservice.storage.js +1 -4
  129. package/storages/microservice.storage.js.map +1 -1
  130. package/storages/property.storage.d.ts +2 -1
  131. package/storages/property.storage.js +3 -5
  132. package/storages/property.storage.js.map +1 -1
  133. package/templates/body-method-template.hbs +7 -0
  134. package/templates/index-template.hbs +5 -5
  135. package/templates/method-template.hbs +16 -6
  136. package/templates/mock-method-template.hbs +19 -0
  137. package/templates/mock-module-template.hbs +1 -1
  138. package/templates/module-template.hbs +8 -4
  139. package/templates/service-template.hbs +10 -2
  140. package/templates/skill-template.hbs +106 -0
  141. package/type-helpers/intersection-type.helper.js +7 -10
  142. package/type-helpers/intersection-type.helper.js.map +1 -1
  143. package/type-helpers/omit-type.helper.js +7 -10
  144. package/type-helpers/omit-type.helper.js.map +1 -1
  145. package/type-helpers/partial-type.helper.js +7 -10
  146. package/type-helpers/partial-type.helper.js.map +1 -1
  147. package/type-helpers/pick-type.helper.js +7 -10
  148. package/type-helpers/pick-type.helper.js.map +1 -1
  149. package/types/document-module-option.type.d.ts +1 -1
  150. package/types/document-module-option.type.js +1 -2
  151. package/types/document.type.js +1 -2
  152. package/types/metadata-parameter-option.type.d.ts +6 -0
  153. package/types/metadata-parameter-option.type.js +2 -0
  154. package/types/metadata-parameter-option.type.js.map +1 -0
  155. package/types/mock-option.type.js +1 -2
  156. package/types/parameter-option.type.d.ts +6 -0
  157. package/types/parameter-option.type.js +2 -0
  158. package/types/parameter-option.type.js.map +1 -0
  159. package/types/property-option.type.d.ts +1 -1
  160. package/types/property-option.type.js +1 -2
  161. package/types/sdk-build-config.type.d.ts +5 -0
  162. package/types/sdk-build-config.type.js +1 -2
package/README.md CHANGED
@@ -3,35 +3,83 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <b>nestjs-grpc-helper</b> simplifies gRPC integration in NestJS, allowing seamless communication between services. It enables easy setup of gRPC clients and servers, and supports building SDK packages that any service can import and use, ensuring consistent API interaction across your microservices architecture.
6
+ <b>nestjs-grpc-helper</b> simplifies gRPC integration in NestJS. Define your microservices with decorators, and the library generates the proto files, a fully typed TypeScript SDK, interactive documentation, and mock data keeping every consumer of your services consistent and type-safe.
7
7
  </p>
8
8
 
9
- ## Installation 🤖
9
+ ## Table of Contents 📚
10
+
11
+ - [How It Works](#how-it-works-)
12
+ - [Installation](#installation-)
13
+ - [Quick Start](#quick-start-)
14
+ - [Defining DTOs and Responses](#defining-dtos-and-responses-)
15
+ - [Decorator Reference](#decorator-reference-)
16
+ - [Type Helpers](#type-helpers-)
17
+ - [Mock Data](#mock-data-)
18
+ - [Generating an SDK](#generating-an-sdk-)
19
+ - [Using a Generated SDK](#using-a-generated-sdk-)
20
+ - [Documentation UI](#documentation-ui-)
21
+ - [Custom gRPC Client](#custom-grpc-client-)
22
+ - [Translation Support](#translation-support-)
23
+ - [AI Agent Skill](#ai-agent-skill-)
24
+ - [License](#license-)
25
+
26
+ ## How It Works 🧠
27
+
28
+ The library follows a metadata-driven code generation flow:
10
29
 
11
- Install the `nestjs-grpc-helper` package with:
30
+ 1. **Decorators** such as `@RegisterGrpcMicroservice`, `@GrpcAction`, and `@Property` attach metadata to your classes at
31
+ load time.
32
+ 2. From that metadata, the library can generate a **`.proto` file**, a **TypeScript SDK package** that other services
33
+ import for type-safe calls, an **interactive documentation UI**, and **mock implementations** for testing.
34
+
35
+ You write your service once; everything downstream is derived from it.
36
+
37
+ ## Installation 🤖
12
38
 
13
39
  ```bash
14
40
  npm install @hodfords/nestjs-grpc-helper --save
15
41
  ```
16
42
 
17
- Next, automatically generate the proto file and include it in main.ts before starting the application:
43
+ Responses must follow the [@hodfords/nestjs-response](https://www.npmjs.com/package/@hodfords/nestjs-response)
44
+ conventions, and the `make-sdk` / `update-ai-skill` commands run through
45
+ [@hodfords/nestjs-command](https://www.npmjs.com/package/@hodfords/nestjs-command).
46
+
47
+ ## Quick Start 🚀
48
+
49
+ ### 1. Define a request DTO and a response
18
50
 
19
51
  ```typescript
20
- import { generateProtoService } from '@hodfords/nestjs-grpc-helper';
52
+ import { Property } from '@hodfords/nestjs-grpc-helper';
53
+ import { IsString, IsOptional } from 'class-validator';
21
54
 
22
- generateProtoService(camelCase(env.APP_NAME), env.ROOT_PATH + '/../');
23
- ```
55
+ export class GetUserByIdDto {
56
+ @Property({ type: String, description: 'User id to look up' })
57
+ @IsString()
58
+ userId: string;
59
+ }
24
60
 
25
- Alternatively, generate it on demand with the `make:proto` command (see [Create proto file](#create-proto-file)).
61
+ export class UserResponse {
62
+ @Property({ type: String, required: false })
63
+ @IsString()
64
+ @IsOptional()
65
+ name?: string;
26
66
 
27
- ## Usage 🚀
67
+ @Property({ type: Boolean, required: false })
68
+ isAdmin?: boolean;
69
+ }
70
+ ```
28
71
 
29
- ### Creating microservices
72
+ ### 2. Define the microservice
30
73
 
31
- Create microservices using the `@GrpcMicroservice` decorator, similar to how you would use a Controller. Ensure that the response adheres to the [nestjs-response](https://www.npmjs.com/package/@hodfords/nestjs-response) rules:
74
+ A gRPC microservice is declared like a controller. Each `@GrpcAction` method becomes an rpc in the generated proto and a
75
+ method in the generated SDK:
32
76
 
33
77
  ```typescript
34
- @GrpcMicroservice()
78
+ import { GrpcAction, GrpcValue, RegisterGrpcMicroservice } from '@hodfords/nestjs-grpc-helper';
79
+ import { ResponseModel } from '@hodfords/nestjs-response';
80
+
81
+ @Controller()
82
+ @RegisterGrpcMicroservice('User microservice')
35
83
  export class UserMicroservice {
36
84
  constructor(private userService: UserService) {}
37
85
 
@@ -43,72 +91,276 @@ export class UserMicroservice {
43
91
  }
44
92
  ```
45
93
 
46
- ### Any Type
94
+ `@ResponseModel` supports single models, arrays, primitives, and nullable results:
95
+
96
+ ```typescript
97
+ @ResponseModel(UserResponse) // single object
98
+ @ResponseModel(UserResponse, true) // array of objects
99
+ @ResponseModel(String) // primitive (String, Number, Boolean)
100
+ @ResponseModel(UserResponse, { isAllowEmpty: true }) // object or null
101
+ ```
102
+
103
+ ### 3. Generate the proto file and start the gRPC server
47
104
 
48
- You can use any type if fixed types are not an option. However, since it’s passed as JSON, the performance may not be as optimal as with binary. Consider using binary if performance is a concern.
105
+ Generate the proto file before the application starts, then connect the gRPC microservice:
49
106
 
50
107
  ```typescript
51
- @Property({ type: String, format: 'any', required: false })
108
+ import { generateProtoService } from '@hodfords/nestjs-grpc-helper';
109
+ import { Transport } from '@nestjs/microservices';
110
+ import path from 'path';
111
+
112
+ generateProtoService('packageName', path.join(__dirname, '../../proto'));
113
+
114
+ async function bootstrap() {
115
+ const app = await NestFactory.create(AppModule);
116
+ app.connectMicroservice<GrpcOptions>({
117
+ transport: Transport.GRPC,
118
+ options: {
119
+ url: '0.0.0.0:50059',
120
+ package: 'packageName',
121
+ protoPath: path.join(__dirname, '../../proto/microservice.proto')
122
+ }
123
+ });
124
+ await app.startAllMicroservices();
125
+ await app.listen(3000);
126
+ }
127
+ ```
128
+
129
+ ## Defining DTOs and Responses 📦
130
+
131
+ `@Property` is the single source of truth for a field. It registers the field for proto generation, SDK generation, and
132
+ Swagger documentation at the same time.
133
+
134
+ ```typescript
135
+ export class FindManyDto {
136
+ @Property({ type: 'string', description: 'Name of user to search' })
137
+ @IsString()
138
+ name: string;
139
+
140
+ @Property({ type: ParamNestedDto, isArray: true, required: true })
141
+ nestedDto: ParamNestedDto[];
142
+
143
+ @Property({ type: String, required: false, enum: UserTypeEnum, enumName: 'UserTypeEnum' })
144
+ @IsEnum(UserTypeEnum)
145
+ @IsOptional()
146
+ type?: UserTypeEnum;
147
+ }
148
+ ```
149
+
150
+ Commonly used options (all [ApiPropertyOptions](https://docs.nestjs.com/openapi/types-and-parameters) are also
151
+ accepted):
152
+
153
+ | Option | Description |
154
+ | ------------------- | ------------------------------------------------------------------------------------------- |
155
+ | `type` | `String`, `Number`, `Boolean`, a class reference, a lazy `() => Class`, or a string literal |
156
+ | `isArray` | Marks the field as repeated |
157
+ | `required` | `false` makes the field optional in the proto and SDK |
158
+ | `description` | Description used in documentation and the AI skill |
159
+ | `format` | Refines numbers (`'int32'`, `'float'`, …) or marks a string as dynamic JSON (`'any'`) |
160
+ | `enum` / `enumName` | Declares an enum field; `enumName` names the generated enum |
161
+
162
+ ### Dynamic (`any`) fields
163
+
164
+ For values without a fixed schema, combine `format: 'any'` with `@AnyType`. The value is serialized to JSON on the wire
165
+ and parsed back transparently:
166
+
167
+ ```typescript
168
+ @Property({ type: 'string', format: 'any' })
52
169
  @AnyType()
53
170
  data: any;
54
171
  ```
55
172
 
56
- ### Create SDK
173
+ ## Decorator Reference 🏷️
174
+
175
+ ### Service and method decorators
176
+
177
+ | Decorator | Description |
178
+ | ----------------------------------------- | ------------------------------------------------------------------------------------------- |
179
+ | `@RegisterGrpcMicroservice(description?)` | Marks a class as a gRPC microservice |
180
+ | `@GrpcAction(description?)` | Marks a method as a gRPC action/endpoint |
181
+ | `@SdkFlattenParams()` | Flattens the request DTO's properties into individual arguments in the generated SDK method |
182
+
183
+ ### Request parameter decorators
184
+
185
+ | Decorator | Description |
186
+ | -------------------- | ----------------------------------------------------------------------------- |
187
+ | `@GrpcValue()` | Marks a parameter as the request body (used with a DTO type) |
188
+ | `@GrpcParam(option)` | Defines a direct request parameter with name, type, and validation decorators |
189
+ | `@GrpcId(name)` | Shortcut for a required UUID string parameter (`IsNotEmpty` + `IsUUID`) |
190
+ | `@GrpcIds(name)` | Shortcut for a required array of UUID strings |
191
+ | `@GrpcEnum(option)` | Enum parameter with automatic type detection and `IsEnum` validation |
192
+ | `@GrpcEnums(option)` | Array variant of `@GrpcEnum` |
193
+ | `@GrpcPagination()` | Built-in pagination parameter (`page`, `perPage`) |
194
+ | `@GrpcSort()` | Built-in sort parameter (`sortField`, `sortDirection: 'ASC' \| 'DESC'`) |
195
+
196
+ Direct parameters can be mixed with a `@GrpcValue` body and gRPC metadata in the same method:
197
+
198
+ ```typescript
199
+ @GrpcAction('List users with pagination, sorting, and workspace scoping')
200
+ @ResponseModel(UserResponse, true)
201
+ listUsers(
202
+ @GrpcValue() param: FilterDto,
203
+ @GrpcPagination() pagination: PaginationDto,
204
+ @GrpcSort() sortParam: SortDto,
205
+ @GrpcMetadataId('workspace-id') workspaceId: string
206
+ ): Promise<UserResponse[]> { ... }
207
+ ```
208
+
209
+ ### Metadata decorators
210
+
211
+ | Decorator | Description |
212
+ | ----------------------- | -------------------------------------------------- |
213
+ | `@GrpcMetadata(option)` | Extracts a value from gRPC metadata (like headers) |
214
+ | `@GrpcMetadataId(name)` | Shortcut for a UUID metadata field |
215
+
216
+ ### Property and type decorators
217
+
218
+ | Decorator | Description |
219
+ | --------------------- | ----------------------------------------------------------------------------------------- |
220
+ | `@Property(option)` | Defines a DTO/response field with type, validation, and Swagger metadata |
221
+ | `@AnyType(option?)` | JSON serialization for dynamic `any` fields (`{ isDto: true }` parses into the DTO class) |
222
+ | `@ExtendType(Parent)` | Inherits the parent's property metadata when extending a composed type |
223
+ | `@SdkExpose()` | Forces a class into the generated SDK even when no rpc references it |
224
+
225
+ ## Type Helpers 🧬
226
+
227
+ Compose DTOs while preserving the property metadata needed for proto and SDK generation. These mirror the
228
+ `@nestjs/swagger` mapped types:
229
+
230
+ ```typescript
231
+ import {
232
+ PickResponseType,
233
+ OmitResponseType,
234
+ PartialResponseType,
235
+ IntersectionResponseType
236
+ } from '@hodfords/nestjs-grpc-helper';
237
+
238
+ export class UserSummary extends PickResponseType(UserResponse, ['id', 'name']) {}
239
+ export class UserWithoutEmail extends OmitResponseType(UserResponse, ['email']) {}
240
+ export class UpdateUserDto extends PartialResponseType(UserResponse) {}
241
+ export class FullUser extends IntersectionResponseType(UserResponse, ProfileResponse) {}
242
+ ```
243
+
244
+ ## Mock Data 🎭
245
+
246
+ Mock generation powers both the documentation UI and the mock SDK module. Property-level decorators describe how each
247
+ field is faked; response-level decorators override the result of a whole method.
248
+
249
+ ### Property-level decorators
250
+
251
+ | Decorator | Description |
252
+ | ---------------------------- | -------------------------------------------- |
253
+ | `@MockMethod(method, args?)` | Generates the value with a Faker method |
254
+ | `@MockSample(value)` | Uses a fixed value |
255
+ | `@MockNested(maxSize?)` | Generates nested objects (or arrays of them) |
256
+
257
+ ```typescript
258
+ export class UserResponse {
259
+ @Property({ type: String, required: false })
260
+ @MockMethod('faker.person.firstName')
261
+ name?: string;
262
+
263
+ @Property({ type: String, enum: UserTypeEnum, enumName: 'UserTypeEnum' })
264
+ @MockSample(UserTypeEnum.STANDARD)
265
+ type: UserTypeEnum;
266
+
267
+ @Property({ type: AddressResponse, isArray: true })
268
+ @MockNested(5)
269
+ addresses: AddressResponse[];
270
+ }
271
+ ```
272
+
273
+ ### Response-level decorators
57
274
 
58
- To generate a TypeScript SDK for your gRPC services, you can use the `make-sdk` command. This command will automatically generate the necessary proto files and package them into a JavaScript SDK.
59
- You also need the following configuration in your sdk-config.json file:
275
+ | Decorator | Description |
276
+ | ------------------------------------ | ------------------------------------------------------------------- |
277
+ | `@MockResponseSample(value)` | The mocked method returns this fixed value |
278
+ | `@MockResponseMethod(method, args?)` | The mocked method returns the result of a Faker method |
279
+ | `@MockResponseCallback(callback)` | Full control: receives the request arguments plus `(sample, model)` |
280
+
281
+ ```typescript
282
+ @GrpcAction('Check if a user is active')
283
+ @ResponseModel(Boolean)
284
+ @MockResponseSample(true)
285
+ checkUserActive(@GrpcValue() param: AnyDto): Promise<boolean> { ... }
286
+
287
+ @GrpcAction('Count users')
288
+ @ResponseModel(Number)
289
+ @MockResponseMethod('faker.number.int', [{ min: 1, max: 100 }])
290
+ countUsers(@GrpcValue() param: AnyDto): Promise<number> { ... }
291
+
292
+ @GrpcAction('Get users by name')
293
+ @ResponseModel(UserResponse, true)
294
+ @MockResponseCallback((param: AnyDto, sample, model) => sample(model))
295
+ getUsersByName(@GrpcValue() param: AnyDto): Promise<UserResponse[]> { ... }
296
+ ```
297
+
298
+ ### Generating mock instances programmatically
299
+
300
+ ```typescript
301
+ import { sample } from '@hodfords/nestjs-grpc-helper';
302
+
303
+ const mockUser = sample(UserResponse);
304
+ ```
305
+
306
+ ## Generating an SDK 🛠️
307
+
308
+ The `make-sdk` command collects every request and response type reachable from your `@GrpcAction` methods, generates the
309
+ proto file, and packages everything into a TypeScript SDK that other services install like any npm package.
310
+
311
+ Add an `sdk-config.json` to your project root:
60
312
 
61
313
  ```json
62
314
  {
63
- "name": "sdkName",
64
- "packageName": "@hodfords/package-name",
65
- "format": true,
66
- "build": true,
67
- "output": "sdk",
68
- "outputBuild": "sdkBuild",
69
- "removeOutput": true,
70
- "addAllowDecorator": true,
71
- "tsconfig": {
72
- "extends": "./tsconfig.json",
73
- "compilerOptions": {
74
- "outDir": "sdkBuild"
315
+ "name": "sdkName",
316
+ "packageName": "@hodfords/package-name",
317
+ "format": true,
318
+ "build": true,
319
+ "output": "sdk",
320
+ "outputBuild": "sdkBuild",
321
+ "removeOutput": true,
322
+ "addAllowDecorator": true,
323
+ "aiSkill": {
324
+ "name": "sdkName",
325
+ "description": "A description of the SDK"
75
326
  },
76
- "include": ["sdk"]
77
- }
327
+ "tsconfig": {
328
+ "extends": "./tsconfig.json",
329
+ "compilerOptions": {
330
+ "outDir": "sdkBuild"
331
+ },
332
+ "include": ["sdk"]
333
+ }
78
334
  }
79
335
  ```
80
- Details of the configuration:
81
336
 
82
- | Field | Description |
83
- |-------------------|-------------------------------------------------------|
84
- | name | Name of the SDK |
85
- | packageName | Name of the package |
86
- | format | Format the generated code |
87
- | build | Build the generated code |
88
- | output | Output directory for the generated code |
89
- | outputBuild | Output directory for the built code |
90
- | removeOutput | Remove the output directory |
91
- | addAllowDecorator | Add the allow decorator, need class-validator package |
92
- | tsconfig | TypeScript configuration |
337
+ | Field | Description |
338
+ | ------------------- | -------------------------------------------------------------------------------- |
339
+ | `name` | SDK name; also used as the proto package and gRPC service prefix |
340
+ | `packageName` | npm package name of the generated SDK |
341
+ | `format` | Format the generated code with Prettier |
342
+ | `build` | Compile the generated code after generation |
343
+ | `output` | Output directory for the generated source |
344
+ | `outputBuild` | Output directory for the compiled build |
345
+ | `removeOutput` | Clear the output directory before generating |
346
+ | `addAllowDecorator` | Add `@Allow()` to generated models (requires `class-validator`) |
347
+ | `tsconfig` | TypeScript configuration used to build the SDK |
348
+ | `aiSkill` | Optional. Generates `SKILL.md` and `skill.json` describing the SDK for AI agents |
349
+
350
+ Then run:
93
351
 
94
-
95
- To generate the SDK, run the following command:
96
352
  ```shell
97
353
  npm run wz-command make-sdk
98
354
  ```
99
355
 
100
- #### What this command does
101
-
102
- This command will:
103
-
104
- 1. **Collect all request and response types**: It gathers all `@GrpcValue` request and response types from your project.
105
- 2. **Generate proto file**: Automatically generates the necessary proto files based on the collected types.
106
- 3. **Create JavaScript Package**: Packages the generated code into a JavaScript SDK. The SDK will be published using the name and version specified in your package.json, making it available for other services to import and use. The arguments, response structure, and method names remain consistent with the definitions in your gRPC service, ensuring seamless integration and functionality across services.
356
+ The generated package contains the proto file, a typed service class per microservice, all models and enums, a dynamic
357
+ module for registration, and a mock module for testing. It is published under the name and version from your
358
+ `package.json`, and its method names, arguments, and response types match your service definitions exactly.
107
359
 
108
- ### Create proto file
360
+ ### Generating only the proto file
109
361
 
110
- To generate only the proto file, without building the whole SDK, use the `make:proto` command. It reuses the same
111
- `sdk-config.json` file as `make-sdk`: `name` is used as the proto package and `output` as the destination directory.
362
+ To generate just the proto file, without building the whole SDK, use the `make:proto` command. It reuses the same
363
+ `sdk-config.json`: `name` is used as the proto package and `output` as the destination directory.
112
364
 
113
365
  ```shell
114
366
  npm run wz-command make:proto
@@ -120,103 +372,136 @@ Both arguments are optional:
120
372
  npm run wz-command make:proto sdk-config.json ./proto
121
373
  ```
122
374
 
123
- | Argument | Description |
124
- |------------|------------------------------------------------------------------------|
125
- | configFile | Config file to read. Defaults to `sdk-config.json` |
126
- | outputPath | Directory the `microservice.proto` file is written into. Defaults to the `output` field of the config file |
375
+ | Argument | Description |
376
+ | ------------ | ----------------------------------------------------------------------------------------------------------- |
377
+ | `configFile` | Config file to read. Defaults to `sdk-config.json` |
378
+ | `outputPath` | Directory the `microservice.proto` file is written into. Defaults to the `output` field of the config file |
127
379
 
128
- ### SDK usage
380
+ ## Using a Generated SDK 📥
129
381
 
130
- After publishing the SDK, other services can easily integrate it. Here’s an example of how to use the generated SDK
382
+ ### 1. Register the SDK module
131
383
 
132
- 1. **Import the sdk package**
384
+ ```typescript
385
+ SdkNameModule.register({
386
+ url: env.GRPC_URL,
387
+ timeout: 5000
388
+ });
389
+ ```
133
390
 
134
- 2. **Register the microservice module**: Configure the microservice in `AppModule` with the appropriate gRPC URL and timeout settings.
391
+ Available options (`MicroserviceModuleOptionType`):
135
392
 
136
- ```typescript
137
- UserModule.register({
138
- url: env.GRPC_URL,
139
- timeout: 5000
140
- });
141
- ```
393
+ | Option | Description |
394
+ | ------------------------- | ------------------------------------------------------------------------ |
395
+ | `url` | gRPC server address |
396
+ | `timeout` | Request timeout in milliseconds |
397
+ | `ssl` | Use SSL credentials |
398
+ | `maxReceiveMessageLength` | Max incoming message size (default 4MB) |
399
+ | `shouldLoadEmptyArray` | Deserialize absent repeated fields as `[]` |
400
+ | `requestInitializer` | Callback to enrich the outgoing `Metadata` (auth tokens, request ids, …) |
401
+ | `…` | Any other `@grpc/grpc-js` channel option is passed through |
142
402
 
143
- 3. **Use the SDK in another service**: Import the SDK and use it to interact with your gRPC services.
403
+ ### 2. Inject the service and call it
144
404
 
145
- ```typescript
146
- export class OtherService {
147
- constructor(private userMicroservice: UserMicroservice) {}
405
+ ```typescript
406
+ export class OtherService {
407
+ constructor(private userMicroservice: UserMicroservice) {}
148
408
 
149
- async doTask(userId: string): Promise<void> {
150
- const user = await this.userMicroservice.findUserById({ id: userId });
151
- // Process user information as needed
152
- }
409
+ async doTask(userId: string): Promise<void> {
410
+ const user = await this.userMicroservice.findUserById({ userId });
153
411
  }
154
- ```
412
+ }
413
+ ```
155
414
 
156
- In this example, `OtherService` uses the `UserMicroservice` class from the SDK to call the `findUserById` method.
415
+ Calls are fully typed, request DTOs are serialized through their models, responses are transformed back into model
416
+ instances, and gRPC errors are translated into NestJS `HttpException`s (including timeouts).
157
417
 
158
- ### Mock response
418
+ ### 3. Mock module for tests
159
419
 
160
- To effectively generate and handle mock data in your application, you can use the `@MockMethod`, `@MockSample`, and `@MockNested` decorators.
420
+ Every SDK ships a mock module that provides the same service classes backed by the mock decorators no gRPC server
421
+ required:
161
422
 
162
- ##### Generate dynamic data with `@MockMethod`
423
+ ```typescript
424
+ imports: [MockSdkNameModule];
425
+ ```
163
426
 
164
- Use `@MockMethod` to apply Faker methods for generating random values.
427
+ ## Documentation UI 🖥️
165
428
 
166
- For example, to create a random string of 10 characters
429
+ The library serves an interactive UI for browsing and testing your gRPC services at
430
+ `http://your-host/microservice-documents`:
167
431
 
168
432
  ```typescript
169
- @Property({ type: String, required: false })
170
- @MockMethod('faker.datatype.string', [10])
171
- @IsString()
172
- name: string;
433
+ MicroserviceDocumentModule.register({
434
+ isEnable: env.NODE_ENV !== 'production',
435
+ packageName: 'packageName',
436
+ clientOptions: {
437
+ customClass: CustomGrpcClient,
438
+ options: {
439
+ url: '0.0.0.0:50059',
440
+ package: 'packageName',
441
+ protoPath: path.join(__dirname, '../../proto/microservice.proto')
442
+ }
443
+ }
444
+ });
173
445
  ```
174
446
 
175
- ##### Set fixed values with `@MockSample`
447
+ | Option | Description |
448
+ | --------------- | -------------------------------------------------------- |
449
+ | `isEnable` | Toggles the module (pass `false` to disable it entirely) |
450
+ | `packageName` | The proto package name |
451
+ | `clientOptions` | gRPC client options used by the "try it" feature |
452
+ | `prefix` | Optional URL prefix for the documentation routes |
453
+ | `waitingTime` | Optional delay before the client connects on startup |
176
454
 
177
- If you need to set a fixed value for a property, use the `@MockSample` decorator. This is useful for enumerations or other predefined values.
455
+ ## Custom gRPC Client 🔌
178
456
 
179
- For example, to set a fixed user type
457
+ `CustomGrpcClient` extends NestJS's `ClientGrpcProxy` with per-service client caching and support for every gRPC channel
458
+ option:
180
459
 
181
460
  ```typescript
182
- @Property({
183
- type: String,
184
- enum: UserTypeEnum,
185
- enumName: 'UserTypeEnum'
186
- })
187
- @MockSample(UserTypeEnum.STANDARD)
188
- @IsEnum(UserTypeEnum)
189
- type: UserTypeEnum;
461
+ import { CustomGrpcClient } from '@hodfords/nestjs-grpc-helper';
462
+
463
+ {
464
+ customClass: CustomGrpcClient,
465
+ options: {
466
+ maxSendMessageLength: 1024 * 1024 * 50, // 50MB max outgoing message
467
+ maxReceiveMessageLength: 1024 * 1024 * 50, // 50MB max incoming message
468
+ keepaliveTimeMs: 120000, // Keepalive ping interval
469
+ keepaliveTimeoutMs: 20000, // Keepalive timeout
470
+ keepalivePermitWithoutCalls: 1 // Allow pings without active calls
471
+ }
472
+ }
190
473
  ```
191
474
 
192
- ##### Generate nested data
475
+ Generated SDK modules use it automatically.
193
476
 
194
- Use `@MockNested` to generate mock data for nested objects or arrays of nested objects.
477
+ ## Translation Support 🌍
195
478
 
196
- For example, to create an array of 5 nested objects
479
+ Use `GrpcTranslationInterceptor` to extract the caller's language from gRPC metadata and run the handler in that
480
+ language context (via
481
+ [@hodfords/nestjs-cls-translation](https://www.npmjs.com/package/@hodfords/nestjs-cls-translation)):
197
482
 
198
483
  ```typescript
199
- @Property({ type: UserResponse, isArray: true })
200
- @IsArray()
201
- @ValidateNested()
202
- @Type(() => UserResponse)
203
- @MockNested(5)
204
- users: UserResponse[];
484
+ @UseInterceptors(GrpcTranslationInterceptor)
485
+ @GrpcAction('Get user')
486
+ @ResponseModel(UserResponse)
487
+ getUser(@GrpcValue() dto: GetUserDto): Promise<UserEntity> {
488
+ return this.userService.getUser(dto.id);
489
+ }
205
490
  ```
206
491
 
207
- ### Document for GRPC
492
+ ## AI Agent Skill 🤝
208
493
 
209
- You can go to `http://xyz/microservice-documents` to check and try to call the gRPC method
494
+ When `aiSkill` is configured in `sdk-config.json`, the generated SDK ships with a `SKILL.md` and `skill.json` that
495
+ describe your services, models, and enums in a format AI agents can consume. Consumers of the SDK can install those
496
+ skills into their project with:
210
497
 
211
- ```typescript
212
- MicroserviceDocumentModule.register({
213
- isEnable: true,
214
- prefix: <app-prefix>,
215
- packageName: camelCase(<package-name>),
216
- clientOptions: { ...microserviceGrpcConfig, customClass: CustomGrpcClient, transport: undefined }
217
- })
498
+ ```shell
499
+ npm run wz-command update-ai-skill "@hodfords/*" claude
218
500
  ```
219
501
 
502
+ The first argument is a package name pattern matched against `node_modules`; the second selects the agent — `claude`
503
+ (installs into `.claude/skills`) or `antigravity` (installs into `.agent/skills`).
504
+
220
505
  ## License 📝
221
506
 
222
507
  This project is licensed under the MIT License
@@ -1,4 +1,4 @@
1
- import { Logger } from '@nestjs/common/services/logger.service';
1
+ import { Logger } from '@nestjs/common/services/logger.service.js';
2
2
  import { ClientGrpc, ClientProxy, GrpcOptions } from '@nestjs/microservices';
3
3
  import { Observable } from 'rxjs';
4
4
  export declare class CustomGrpcClient extends ClientProxy implements ClientGrpc {