@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.
- package/README.md +403 -118
- package/clients/custom-grpc.client.d.ts +1 -1
- package/clients/custom-grpc.client.js +37 -36
- package/clients/custom-grpc.client.js.map +1 -1
- package/commands/generate-proto.command.js +11 -12
- package/commands/generate-proto.command.js.map +1 -1
- package/commands/generate-sdk.command.js +11 -12
- package/commands/generate-sdk.command.js.map +1 -1
- package/commands/update-ai-skill.command.d.ts +6 -0
- package/commands/update-ai-skill.command.js +78 -0
- package/commands/update-ai-skill.command.js.map +1 -0
- package/constants/metadata-key.const.d.ts +7 -0
- package/constants/metadata-key.const.js +8 -0
- package/constants/metadata-key.const.js.map +1 -0
- package/decorators/any-type.decorator.js +3 -6
- package/decorators/any-type.decorator.js.map +1 -1
- package/decorators/extend-type.decorator.js +8 -11
- package/decorators/extend-type.decorator.js.map +1 -1
- package/decorators/grpc-metadata.decorator.d.ts +3 -0
- package/decorators/grpc-metadata.decorator.js +24 -0
- package/decorators/grpc-metadata.decorator.js.map +1 -0
- package/decorators/grpc-param.decorator.d.ts +15 -0
- package/decorators/grpc-param.decorator.js +90 -0
- package/decorators/grpc-param.decorator.js.map +1 -0
- package/decorators/grpc-value.decorator.js +3 -7
- package/decorators/grpc-value.decorator.js.map +1 -1
- package/decorators/microservice.decorator.js +29 -19
- package/decorators/microservice.decorator.js.map +1 -1
- package/decorators/mock.decorator.d.ts +2 -1
- package/decorators/mock.decorator.js +16 -16
- package/decorators/mock.decorator.js.map +1 -1
- package/decorators/property.decorator.d.ts +1 -1
- package/decorators/property.decorator.js +10 -10
- package/decorators/property.decorator.js.map +1 -1
- package/decorators/sdk-expose.decorator.d.ts +3 -0
- package/decorators/sdk-expose.decorator.js +8 -0
- package/decorators/sdk-expose.decorator.js.map +1 -0
- package/documents/grpc-test.dto.d.ts +1 -0
- package/documents/grpc-test.dto.js +25 -19
- package/documents/grpc-test.dto.js.map +1 -1
- package/documents/microservice-document.controller.d.ts +3 -3
- package/documents/microservice-document.controller.js +27 -18
- package/documents/microservice-document.controller.js.map +1 -1
- package/documents/microservice-document.module.d.ts +1 -1
- package/documents/microservice-document.module.js +20 -22
- package/documents/microservice-document.module.js.map +1 -1
- package/dto/pagination.dto.d.ts +4 -0
- package/dto/pagination.dto.js +28 -0
- package/dto/pagination.dto.js.map +1 -0
- package/dto/sort.dto.d.ts +4 -0
- package/dto/sort.dto.js +30 -0
- package/dto/sort.dto.js.map +1 -0
- package/helpers/api-property.helper.d.ts +1 -1
- package/helpers/api-property.helper.js +3 -6
- package/helpers/api-property.helper.js.map +1 -1
- package/helpers/flat-param.helper.d.ts +7 -0
- package/helpers/flat-param.helper.js +83 -0
- package/helpers/flat-param.helper.js.map +1 -0
- package/helpers/generate.helper.d.ts +2 -2
- package/helpers/generate.helper.js +9 -14
- package/helpers/generate.helper.js.map +1 -1
- package/helpers/grpc-method.helper.d.ts +7 -0
- package/helpers/grpc-method.helper.js +37 -0
- package/helpers/grpc-method.helper.js.map +1 -0
- package/helpers/metadata-param.helper.d.ts +1 -0
- package/helpers/metadata-param.helper.js +29 -0
- package/helpers/metadata-param.helper.js.map +1 -0
- package/helpers/mock.helper.d.ts +2 -2
- package/helpers/mock.helper.js +30 -18
- package/helpers/mock.helper.js.map +1 -1
- package/helpers/property.helper.d.ts +8 -3
- package/helpers/property.helper.js +63 -27
- package/helpers/property.helper.js.map +1 -1
- package/helpers/proto-type.helper.d.ts +1 -1
- package/helpers/proto-type.helper.js +11 -12
- package/helpers/proto-type.helper.js.map +1 -1
- package/helpers/shell.helper.js +4 -6
- package/helpers/shell.helper.js.map +1 -1
- package/helpers/type.helper.js +1 -4
- package/helpers/type.helper.js.map +1 -1
- package/index.d.ts +23 -20
- package/index.js +23 -36
- package/index.js.map +1 -1
- package/interceptors/grpc-translation.interceptor.js +7 -10
- package/interceptors/grpc-translation.interceptor.js.map +1 -1
- package/package.json +115 -113
- package/responses/native.response.js +18 -24
- package/responses/native.response.js.map +1 -1
- package/sdk-config.json +21 -0
- package/sdk-stub/helpers/grpc.helper.d.ts +3 -1
- package/sdk-stub/helpers/grpc.helper.js +37 -22
- package/sdk-stub/helpers/grpc.helper.js.map +1 -1
- package/sdk-stub/helpers/grpc.helper.spec.ts +237 -0
- package/sdk-stub/helpers/grpc.helper.ts +25 -9
- package/sdk-stub/types/microservice-option.type.d.ts +3 -1
- package/sdk-stub/types/microservice-option.type.js +1 -2
- package/sdk-stub/types/microservice-option.type.ts +3 -1
- package/services/generate-document.service.d.ts +2 -2
- package/services/generate-document.service.js +46 -47
- package/services/generate-document.service.js.map +1 -1
- package/services/generate-microservice.service.d.ts +2 -4
- package/services/generate-microservice.service.js +88 -125
- package/services/generate-microservice.service.js.map +1 -1
- package/services/generate-proto.service.d.ts +4 -2
- package/services/generate-proto.service.js +39 -61
- package/services/generate-proto.service.js.map +1 -1
- package/services/generate-skill.service.d.ts +11 -0
- package/services/generate-skill.service.js +137 -0
- package/services/generate-skill.service.js.map +1 -0
- package/services/hbs-generator.service.d.ts +1 -0
- package/services/hbs-generator.service.js +20 -41
- package/services/hbs-generator.service.js.map +1 -1
- package/services/method-template.service.d.ts +5 -3
- package/services/method-template.service.js +28 -9
- package/services/method-template.service.js.map +1 -1
- package/services/mock-method-template.service.d.ts +5 -3
- package/services/mock-method-template.service.js +19 -22
- package/services/mock-method-template.service.js.map +1 -1
- package/services/mock-module-template.service.d.ts +1 -1
- package/services/mock-module-template.service.js +6 -8
- package/services/mock-module-template.service.js.map +1 -1
- package/services/module-template.service.d.ts +1 -1
- package/services/module-template.service.js +6 -8
- package/services/module-template.service.js.map +1 -1
- package/services/service-template.service.d.ts +2 -2
- package/services/service-template.service.js +8 -11
- package/services/service-template.service.js.map +1 -1
- package/storages/microservice.storage.js +1 -4
- package/storages/microservice.storage.js.map +1 -1
- package/storages/property.storage.d.ts +2 -1
- package/storages/property.storage.js +3 -5
- package/storages/property.storage.js.map +1 -1
- package/templates/body-method-template.hbs +7 -0
- package/templates/index-template.hbs +5 -5
- package/templates/method-template.hbs +16 -6
- package/templates/mock-method-template.hbs +19 -0
- package/templates/mock-module-template.hbs +1 -1
- package/templates/module-template.hbs +8 -4
- package/templates/service-template.hbs +10 -2
- package/templates/skill-template.hbs +106 -0
- package/type-helpers/intersection-type.helper.js +7 -10
- package/type-helpers/intersection-type.helper.js.map +1 -1
- package/type-helpers/omit-type.helper.js +7 -10
- package/type-helpers/omit-type.helper.js.map +1 -1
- package/type-helpers/partial-type.helper.js +7 -10
- package/type-helpers/partial-type.helper.js.map +1 -1
- package/type-helpers/pick-type.helper.js +7 -10
- package/type-helpers/pick-type.helper.js.map +1 -1
- package/types/document-module-option.type.d.ts +1 -1
- package/types/document-module-option.type.js +1 -2
- package/types/document.type.js +1 -2
- package/types/metadata-parameter-option.type.d.ts +6 -0
- package/types/metadata-parameter-option.type.js +2 -0
- package/types/metadata-parameter-option.type.js.map +1 -0
- package/types/mock-option.type.js +1 -2
- package/types/parameter-option.type.d.ts +6 -0
- package/types/parameter-option.type.js +2 -0
- package/types/parameter-option.type.js.map +1 -0
- package/types/property-option.type.d.ts +1 -1
- package/types/property-option.type.js +1 -2
- package/types/sdk-build-config.type.d.ts +5 -0
- 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
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
52
|
+
import { Property } from '@hodfords/nestjs-grpc-helper';
|
|
53
|
+
import { IsString, IsOptional } from 'class-validator';
|
|
21
54
|
|
|
22
|
-
|
|
23
|
-
|
|
55
|
+
export class GetUserByIdDto {
|
|
56
|
+
@Property({ type: String, description: 'User id to look up' })
|
|
57
|
+
@IsString()
|
|
58
|
+
userId: string;
|
|
59
|
+
}
|
|
24
60
|
|
|
25
|
-
|
|
61
|
+
export class UserResponse {
|
|
62
|
+
@Property({ type: String, required: false })
|
|
63
|
+
@IsString()
|
|
64
|
+
@IsOptional()
|
|
65
|
+
name?: string;
|
|
26
66
|
|
|
27
|
-
|
|
67
|
+
@Property({ type: Boolean, required: false })
|
|
68
|
+
isAdmin?: boolean;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
28
71
|
|
|
29
|
-
###
|
|
72
|
+
### 2. Define the microservice
|
|
30
73
|
|
|
31
|
-
|
|
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
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
105
|
+
Generate the proto file before the application starts, then connect the gRPC microservice:
|
|
49
106
|
|
|
50
107
|
```typescript
|
|
51
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
"
|
|
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
|
|
83
|
-
|
|
84
|
-
| name |
|
|
85
|
-
| packageName |
|
|
86
|
-
| format | Format the generated code
|
|
87
|
-
| build |
|
|
88
|
-
| output | Output directory for the generated
|
|
89
|
-
| outputBuild | Output directory for the
|
|
90
|
-
| removeOutput |
|
|
91
|
-
| addAllowDecorator | Add
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
###
|
|
360
|
+
### Generating only the proto file
|
|
109
361
|
|
|
110
|
-
To generate
|
|
111
|
-
`sdk-config.json
|
|
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
|
|
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
|
-
|
|
380
|
+
## Using a Generated SDK 📥
|
|
129
381
|
|
|
130
|
-
|
|
382
|
+
### 1. Register the SDK module
|
|
131
383
|
|
|
132
|
-
|
|
384
|
+
```typescript
|
|
385
|
+
SdkNameModule.register({
|
|
386
|
+
url: env.GRPC_URL,
|
|
387
|
+
timeout: 5000
|
|
388
|
+
});
|
|
389
|
+
```
|
|
133
390
|
|
|
134
|
-
|
|
391
|
+
Available options (`MicroserviceModuleOptionType`):
|
|
135
392
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
403
|
+
### 2. Inject the service and call it
|
|
144
404
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
405
|
+
```typescript
|
|
406
|
+
export class OtherService {
|
|
407
|
+
constructor(private userMicroservice: UserMicroservice) {}
|
|
148
408
|
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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
|
|
418
|
+
### 3. Mock module for tests
|
|
159
419
|
|
|
160
|
-
|
|
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
|
-
|
|
423
|
+
```typescript
|
|
424
|
+
imports: [MockSdkNameModule];
|
|
425
|
+
```
|
|
163
426
|
|
|
164
|
-
|
|
427
|
+
## Documentation UI 🖥️
|
|
165
428
|
|
|
166
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
-
|
|
455
|
+
## Custom gRPC Client 🔌
|
|
178
456
|
|
|
179
|
-
|
|
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
|
-
@
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
475
|
+
Generated SDK modules use it automatically.
|
|
193
476
|
|
|
194
|
-
|
|
477
|
+
## Translation Support 🌍
|
|
195
478
|
|
|
196
|
-
|
|
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
|
-
@
|
|
200
|
-
@
|
|
201
|
-
@
|
|
202
|
-
@
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
492
|
+
## AI Agent Skill 🤝
|
|
208
493
|
|
|
209
|
-
|
|
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
|
-
```
|
|
212
|
-
|
|
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 {
|