@jdevel/tnest 0.0.1 → 0.0.2
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 +357 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +8 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/typed-client-factory.d.ts +6 -0
- package/dist/client/typed-client-factory.js +25 -0
- package/dist/client/typed-client-factory.js.map +1 -0
- package/dist/client/typed-client.d.ts +11 -0
- package/dist/client/typed-client.js +22 -0
- package/dist/client/typed-client.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -0
- package/dist/contracts/command.d.ts +6 -0
- package/dist/contracts/command.js +3 -0
- package/dist/contracts/command.js.map +1 -0
- package/dist/contracts/define-helpers.d.ts +12 -0
- package/dist/contracts/define-helpers.js +19 -0
- package/dist/contracts/define-helpers.js.map +1 -0
- package/dist/contracts/event.d.ts +5 -0
- package/dist/contracts/event.js +3 -0
- package/dist/contracts/event.js.map +1 -0
- package/dist/contracts/index.d.ts +6 -0
- package/dist/contracts/index.js +9 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/query.d.ts +6 -0
- package/dist/contracts/query.js +3 -0
- package/dist/contracts/query.js.map +1 -0
- package/dist/contracts/registry.d.ts +8 -0
- package/dist/contracts/registry.js +3 -0
- package/dist/contracts/registry.js.map +1 -0
- package/dist/contracts/utility-types.d.ts +21 -0
- package/dist/contracts/utility-types.js +3 -0
- package/dist/contracts/utility-types.js.map +1 -0
- package/dist/handlers/handler-types.d.ts +4 -0
- package/dist/handlers/handler-types.js +3 -0
- package/dist/handlers/handler-types.js.map +1 -0
- package/dist/handlers/index.d.ts +3 -0
- package/dist/handlers/index.js +8 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/typed-event-pattern.decorator.d.ts +2 -0
- package/dist/handlers/typed-event-pattern.decorator.js +8 -0
- package/dist/handlers/typed-event-pattern.decorator.js.map +1 -0
- package/dist/handlers/typed-message-pattern.decorator.d.ts +2 -0
- package/dist/handlers/typed-message-pattern.decorator.js +8 -0
- package/dist/handlers/typed-message-pattern.decorator.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/index.js +3 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/module-options.d.ts +18 -0
- package/dist/interfaces/module-options.js +3 -0
- package/dist/interfaces/module-options.js.map +1 -0
- package/dist/serialization/default-serializer.d.ts +5 -0
- package/dist/serialization/default-serializer.js +23 -0
- package/dist/serialization/default-serializer.js.map +1 -0
- package/dist/serialization/index.d.ts +3 -0
- package/dist/serialization/index.js +9 -0
- package/dist/serialization/index.js.map +1 -0
- package/dist/serialization/serializer.interface.d.ts +8 -0
- package/dist/serialization/serializer.interface.js +6 -0
- package/dist/serialization/serializer.interface.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-typed-client.d.ts +20 -0
- package/dist/testing/mock-typed-client.js +36 -0
- package/dist/testing/mock-typed-client.js.map +1 -0
- package/dist/testing/test-contract-module.d.ts +10 -0
- package/dist/testing/test-contract-module.js +31 -0
- package/dist/testing/test-contract-module.js.map +1 -0
- package/dist/tnest.module.d.ts +6 -0
- package/dist/tnest.module.js +77 -7
- package/dist/tnest.module.js.map +1 -1
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +8 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/validate-contract.decorator.d.ts +1 -0
- package/dist/validation/validate-contract.decorator.js +21 -0
- package/dist/validation/validate-contract.decorator.js.map +1 -0
- package/dist/validation/validator.interface.d.ts +4 -0
- package/dist/validation/validator.interface.js +5 -0
- package/dist/validation/validator.interface.js.map +1 -0
- package/package.json +10 -3
package/README.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# @jdevel/tnest
|
|
2
|
+
|
|
3
|
+
Type-safe communication between NestJS microservices.
|
|
4
|
+
|
|
5
|
+
Define your message contracts once as TypeScript types, and the compiler enforces them across every producer and consumer — eliminating runtime type mismatches between services.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Compile-time safety** -- mismatched patterns, payloads, or responses are caught before deployment
|
|
10
|
+
- **Transport-agnostic** -- works with any NestJS transport (TCP, Redis, NATS, RabbitMQ, Kafka, gRPC)
|
|
11
|
+
- **NestJS-native** -- standard modules, decorators, and dependency injection
|
|
12
|
+
- **Zero runtime overhead** -- type enforcement happens at compile time; no runtime schema checking unless you opt in
|
|
13
|
+
- **First-class testing** -- `MockTypedClient` and `TestContractModule` included
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @jdevel/tnest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Peer dependencies:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @nestjs/common @nestjs/microservices reflect-metadata rxjs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Define contracts
|
|
30
|
+
|
|
31
|
+
Contracts describe the messages exchanged between services. There are three kinds:
|
|
32
|
+
|
|
33
|
+
| Type | Purpose | Has response? |
|
|
34
|
+
|------|---------|---------------|
|
|
35
|
+
| `Command` | Write operation (request/response) | Yes |
|
|
36
|
+
| `Query` | Read operation (request/response) | Yes |
|
|
37
|
+
| `Event` | Notification (fire-and-forget) | No |
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// contracts/user.contracts.ts
|
|
41
|
+
import { defineRegistry, command, event, query } from '@jdevel/tnest';
|
|
42
|
+
|
|
43
|
+
interface CreateUserDto {
|
|
44
|
+
email: string;
|
|
45
|
+
name: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface User {
|
|
49
|
+
id: string;
|
|
50
|
+
email: string;
|
|
51
|
+
name: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const userContracts = defineRegistry({
|
|
55
|
+
'user.create': command<CreateUserDto, User>(),
|
|
56
|
+
'user.created': event<{ userId: string; email: string }>(),
|
|
57
|
+
'user.get': query<{ id: string }, User>(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export type UserContracts = typeof userContracts;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can also define contracts with explicit interfaces if you prefer:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import type { Command, Event, Query } from '@jdevel/tnest';
|
|
67
|
+
|
|
68
|
+
export interface UserContracts {
|
|
69
|
+
'user.create': Command<'user.create', CreateUserDto, User>;
|
|
70
|
+
'user.created': Event<'user.created', { userId: string; email: string }>;
|
|
71
|
+
'user.get': Query<'user.get', { id: string }, User>;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. Register the module
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// app.module.ts
|
|
79
|
+
import { Module } from '@nestjs/common';
|
|
80
|
+
import { Transport } from '@nestjs/microservices';
|
|
81
|
+
import { TnestModule } from '@jdevel/tnest';
|
|
82
|
+
|
|
83
|
+
@Module({
|
|
84
|
+
imports: [
|
|
85
|
+
TnestModule.forRoot({
|
|
86
|
+
clients: [
|
|
87
|
+
{
|
|
88
|
+
name: 'USER_SERVICE',
|
|
89
|
+
options: {
|
|
90
|
+
transport: Transport.TCP,
|
|
91
|
+
options: { host: 'localhost', port: 3001 },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
})
|
|
98
|
+
export class AppModule {}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3. Send messages (producer)
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// order.service.ts
|
|
105
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
106
|
+
import { ClientProxy } from '@nestjs/microservices';
|
|
107
|
+
import { TypedClientFactory, TypedClient, getClientToken } from '@jdevel/tnest';
|
|
108
|
+
import { firstValueFrom } from 'rxjs';
|
|
109
|
+
import type { UserContracts } from './contracts/user.contracts';
|
|
110
|
+
|
|
111
|
+
@Injectable()
|
|
112
|
+
export class OrderService {
|
|
113
|
+
private readonly users: TypedClient<UserContracts>;
|
|
114
|
+
|
|
115
|
+
constructor(
|
|
116
|
+
factory: TypedClientFactory,
|
|
117
|
+
@Inject(getClientToken('USER_SERVICE')) proxy: ClientProxy,
|
|
118
|
+
) {
|
|
119
|
+
this.users = factory.create<UserContracts>(proxy);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async createOrder(userId: string) {
|
|
123
|
+
const user = await firstValueFrom(
|
|
124
|
+
this.users.send('user.get', { id: userId }),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
this.users.emit('user.created', {
|
|
128
|
+
userId: user.id,
|
|
129
|
+
email: user.email,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return { orderId: '123', user };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The compiler catches contract violations:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
this.users.send('user.delete', { id: '1' });
|
|
141
|
+
// ~~~~~~~~~~~~ ERROR: not a valid pattern
|
|
142
|
+
|
|
143
|
+
this.users.send('user.get', { name: 'test' });
|
|
144
|
+
// ~~~~~~~~~~~~~~~~ ERROR: expects { id: string }
|
|
145
|
+
|
|
146
|
+
this.users.send('user.created', { userId: '1', email: 'a@b.com' });
|
|
147
|
+
// ~~~~~~~~~~~~~~ ERROR: 'user.created' is an event, use emit()
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 4. Handle messages (consumer)
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// user.controller.ts
|
|
154
|
+
import { Controller } from '@nestjs/common';
|
|
155
|
+
import { TypedMessagePattern, TypedEventPattern } from '@jdevel/tnest';
|
|
156
|
+
import type { UserContracts } from './contracts/user.contracts';
|
|
157
|
+
|
|
158
|
+
@Controller()
|
|
159
|
+
export class UserController {
|
|
160
|
+
@TypedMessagePattern<UserContracts>('user.create')
|
|
161
|
+
async create(payload: { email: string; name: string }) {
|
|
162
|
+
return { id: crypto.randomUUID(), ...payload };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@TypedMessagePattern<UserContracts>('user.get')
|
|
166
|
+
async get(payload: { id: string }) {
|
|
167
|
+
return { id: payload.id, email: 'user@example.com', name: 'Example' };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@TypedEventPattern<UserContracts>('user.created')
|
|
171
|
+
async handleCreated(payload: { userId: string; email: string }) {
|
|
172
|
+
console.log(`User created: ${payload.userId}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Testing
|
|
178
|
+
|
|
179
|
+
`MockTypedClient` records every message and returns configurable canned responses:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { MockTypedClient } from '@jdevel/tnest';
|
|
183
|
+
import { firstValueFrom } from 'rxjs';
|
|
184
|
+
import type { UserContracts } from './contracts/user.contracts';
|
|
185
|
+
|
|
186
|
+
const mock = new MockTypedClient<UserContracts>();
|
|
187
|
+
|
|
188
|
+
mock.setResponse('user.get', {
|
|
189
|
+
id: '42',
|
|
190
|
+
email: 'test@example.com',
|
|
191
|
+
name: 'Test User',
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const user = await firstValueFrom(mock.send('user.get', { id: '42' }));
|
|
195
|
+
// user.id === '42'
|
|
196
|
+
|
|
197
|
+
expect(mock.messages).toEqual([
|
|
198
|
+
{ type: 'send', pattern: 'user.get', payload: { id: '42' } },
|
|
199
|
+
]);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
For integration tests, `TestContractModule` swaps real clients for mocks:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { Test } from '@nestjs/testing';
|
|
206
|
+
import { MockTypedClient, TestContractModule } from '@jdevel/tnest';
|
|
207
|
+
import type { UserContracts } from './contracts/user.contracts';
|
|
208
|
+
|
|
209
|
+
const mock = new MockTypedClient<UserContracts>();
|
|
210
|
+
|
|
211
|
+
const module = await Test.createTestingModule({
|
|
212
|
+
imports: [
|
|
213
|
+
TestContractModule.register([
|
|
214
|
+
{ name: 'USER_SERVICE', mock },
|
|
215
|
+
]),
|
|
216
|
+
],
|
|
217
|
+
providers: [OrderService],
|
|
218
|
+
}).compile();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Async Module Configuration
|
|
222
|
+
|
|
223
|
+
Use `forRootAsync` when transport config comes from `ConfigService` or another async source:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
227
|
+
import { TnestModule } from '@jdevel/tnest';
|
|
228
|
+
import { Transport } from '@nestjs/microservices';
|
|
229
|
+
|
|
230
|
+
TnestModule.forRootAsync({
|
|
231
|
+
imports: [ConfigModule],
|
|
232
|
+
useFactory: (config: ConfigService) => ({
|
|
233
|
+
clients: [
|
|
234
|
+
{
|
|
235
|
+
name: 'USER_SERVICE',
|
|
236
|
+
options: {
|
|
237
|
+
transport: Transport.TCP,
|
|
238
|
+
options: {
|
|
239
|
+
host: config.get('USER_SERVICE_HOST'),
|
|
240
|
+
port: config.get('USER_SERVICE_PORT'),
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
}),
|
|
246
|
+
inject: [ConfigService],
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Runtime Validation (Optional)
|
|
251
|
+
|
|
252
|
+
By default, contracts are enforced at compile time only. To add runtime payload validation, implement the `ContractValidator` interface and apply `@ValidateContract()`:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { Injectable } from '@nestjs/common';
|
|
256
|
+
import {
|
|
257
|
+
CONTRACT_VALIDATOR,
|
|
258
|
+
ValidateContract,
|
|
259
|
+
TypedMessagePattern,
|
|
260
|
+
type ContractValidator,
|
|
261
|
+
} from '@jdevel/tnest';
|
|
262
|
+
|
|
263
|
+
@Injectable()
|
|
264
|
+
class MyValidator implements ContractValidator {
|
|
265
|
+
validate(payload: unknown): void {
|
|
266
|
+
// your validation logic (zod, class-validator, joi, etc.)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Register in module providers
|
|
271
|
+
{ provide: CONTRACT_VALIDATOR, useClass: MyValidator }
|
|
272
|
+
|
|
273
|
+
// Apply to handlers
|
|
274
|
+
@TypedMessagePattern<UserContracts>('user.create')
|
|
275
|
+
@ValidateContract()
|
|
276
|
+
async create(payload: CreateUserDto) {
|
|
277
|
+
// payload has been validated at runtime
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Custom Serialization (Optional)
|
|
282
|
+
|
|
283
|
+
Provide custom payload serialization (protobuf, msgpack, etc.) by implementing `PayloadSerializer` and `PayloadDeserializer`:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import {
|
|
287
|
+
PAYLOAD_SERIALIZER,
|
|
288
|
+
PAYLOAD_DESERIALIZER,
|
|
289
|
+
type PayloadSerializer,
|
|
290
|
+
type PayloadDeserializer,
|
|
291
|
+
} from '@jdevel/tnest';
|
|
292
|
+
|
|
293
|
+
@Injectable()
|
|
294
|
+
class MsgpackSerializer implements PayloadSerializer, PayloadDeserializer {
|
|
295
|
+
serialize(payload: unknown) { return msgpack.encode(payload); }
|
|
296
|
+
deserialize(data: unknown) { return msgpack.decode(data as Buffer); }
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Register in module providers
|
|
300
|
+
{ provide: PAYLOAD_SERIALIZER, useClass: MsgpackSerializer }
|
|
301
|
+
{ provide: PAYLOAD_DESERIALIZER, useClass: MsgpackSerializer }
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Utility Types
|
|
305
|
+
|
|
306
|
+
Extract type information from your contract registry:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import type {
|
|
310
|
+
PayloadOf,
|
|
311
|
+
ResponseOf,
|
|
312
|
+
CommandPatterns,
|
|
313
|
+
EventPatterns,
|
|
314
|
+
QueryPatterns,
|
|
315
|
+
SendablePatterns,
|
|
316
|
+
CommandsOf,
|
|
317
|
+
EventsOf,
|
|
318
|
+
QueriesOf,
|
|
319
|
+
} from '@jdevel/tnest';
|
|
320
|
+
|
|
321
|
+
type Payload = PayloadOf<UserContracts['user.create']>; // CreateUserDto
|
|
322
|
+
type Response = ResponseOf<UserContracts['user.create']>; // User
|
|
323
|
+
type Cmds = CommandPatterns<UserContracts>; // 'user.create'
|
|
324
|
+
type Evts = EventPatterns<UserContracts>; // 'user.created'
|
|
325
|
+
type Qrys = QueryPatterns<UserContracts>; // 'user.get'
|
|
326
|
+
type Sendable = SendablePatterns<UserContracts>; // 'user.create' | 'user.get'
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## API Reference
|
|
330
|
+
|
|
331
|
+
| Export | Kind | Description |
|
|
332
|
+
|--------|------|-------------|
|
|
333
|
+
| `TnestModule` | Module | Dynamic module with `forRoot` / `forRootAsync` |
|
|
334
|
+
| `TypedClient` | Class | Type-safe wrapper around `ClientProxy` |
|
|
335
|
+
| `TypedClientFactory` | Service | Creates `TypedClient` instances |
|
|
336
|
+
| `TypedMessagePattern` | Decorator | Typed `@MessagePattern` for commands/queries |
|
|
337
|
+
| `TypedEventPattern` | Decorator | Typed `@EventPattern` for events |
|
|
338
|
+
| `MockTypedClient` | Class | Test double that records messages |
|
|
339
|
+
| `TestContractModule` | Module | Registers mock clients for testing |
|
|
340
|
+
| `ValidateContract` | Decorator | Opt-in runtime payload validation |
|
|
341
|
+
| `getClientToken` | Function | Returns injection token for a named client |
|
|
342
|
+
| `defineRegistry` | Function | Builder helper for defining contract registries |
|
|
343
|
+
| `command` / `event` / `query` | Functions | Builder helpers for individual contracts |
|
|
344
|
+
| `Command` / `Event` / `Query` | Type | Contract type interfaces |
|
|
345
|
+
| `ContractRegistry` | Type | Base type for a registry of contracts |
|
|
346
|
+
| `PayloadOf` / `ResponseOf` / `PatternOf` | Type | Extract parts of a contract |
|
|
347
|
+
| `CommandsOf` / `EventsOf` / `QueriesOf` | Type | Filter registry by contract kind |
|
|
348
|
+
| `CommandPatterns` / `EventPatterns` / `QueryPatterns` | Type | Pattern string unions by kind |
|
|
349
|
+
| `SendablePatterns` | Type | Union of command + query patterns |
|
|
350
|
+
| `ContractValidator` | Interface | Implement for runtime validation |
|
|
351
|
+
| `PayloadSerializer` / `PayloadDeserializer` | Interface | Implement for custom serialization |
|
|
352
|
+
| `CONTRACT_VALIDATOR` | Token | Injection token for validator |
|
|
353
|
+
| `PAYLOAD_SERIALIZER` / `PAYLOAD_DESERIALIZER` | Token | Injection tokens for serialization |
|
|
354
|
+
|
|
355
|
+
## License
|
|
356
|
+
|
|
357
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypedClientFactory = exports.TypedClient = void 0;
|
|
4
|
+
var typed_client_1 = require("./typed-client");
|
|
5
|
+
Object.defineProperty(exports, "TypedClient", { enumerable: true, get: function () { return typed_client_1.TypedClient; } });
|
|
6
|
+
var typed_client_factory_1 = require("./typed-client-factory");
|
|
7
|
+
Object.defineProperty(exports, "TypedClientFactory", { enumerable: true, get: function () { return typed_client_factory_1.TypedClientFactory; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ClientProxy, type ClientOptions } from '@nestjs/microservices';
|
|
2
|
+
import type { ContractRegistry } from '../contracts';
|
|
3
|
+
import { TypedClient } from './typed-client';
|
|
4
|
+
export declare class TypedClientFactory {
|
|
5
|
+
create<TRegistry extends ContractRegistry>(clientOrOptions: ClientProxy | ClientOptions): TypedClient<TRegistry>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.TypedClientFactory = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const microservices_1 = require("@nestjs/microservices");
|
|
12
|
+
const typed_client_1 = require("./typed-client");
|
|
13
|
+
let TypedClientFactory = class TypedClientFactory {
|
|
14
|
+
create(clientOrOptions) {
|
|
15
|
+
const client = clientOrOptions instanceof microservices_1.ClientProxy
|
|
16
|
+
? clientOrOptions
|
|
17
|
+
: microservices_1.ClientProxyFactory.create(clientOrOptions);
|
|
18
|
+
return new typed_client_1.TypedClient(client);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.TypedClientFactory = TypedClientFactory;
|
|
22
|
+
exports.TypedClientFactory = TypedClientFactory = __decorate([
|
|
23
|
+
(0, common_1.Injectable)()
|
|
24
|
+
], TypedClientFactory);
|
|
25
|
+
//# sourceMappingURL=typed-client-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typed-client-factory.js","sourceRoot":"","sources":["../../src/client/typed-client-factory.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAC5C,yDAA4F;AAE5F,iDAA6C;AAGtC,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC7B,MAAM,CACJ,eAA4C;QAE5C,MAAM,MAAM,GACV,eAAe,YAAY,2BAAW;YACpC,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,kCAAkB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAEjD,OAAO,IAAI,0BAAW,CAAY,MAAM,CAAC,CAAC;IAC5C,CAAC;CACF,CAAA;AAXY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;GACA,kBAAkB,CAW9B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ClientProxy } from '@nestjs/microservices';
|
|
2
|
+
import type { Observable } from 'rxjs';
|
|
3
|
+
import type { ContractRegistry, EventPatterns, PayloadOf, ResponseOf, SendablePatterns } from '../contracts';
|
|
4
|
+
export declare class TypedClient<TRegistry extends ContractRegistry> {
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(client: ClientProxy);
|
|
7
|
+
send<P extends SendablePatterns<TRegistry>>(pattern: P, payload: PayloadOf<TRegistry[P]>): Observable<ResponseOf<TRegistry[P]>>;
|
|
8
|
+
emit<P extends EventPatterns<TRegistry>>(pattern: P, payload: PayloadOf<TRegistry[P]>): Observable<undefined>;
|
|
9
|
+
connect(): Promise<void>;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypedClient = void 0;
|
|
4
|
+
class TypedClient {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
send(pattern, payload) {
|
|
9
|
+
return this.client.send(pattern, payload);
|
|
10
|
+
}
|
|
11
|
+
emit(pattern, payload) {
|
|
12
|
+
return this.client.emit(pattern, payload);
|
|
13
|
+
}
|
|
14
|
+
connect() {
|
|
15
|
+
return this.client.connect();
|
|
16
|
+
}
|
|
17
|
+
close() {
|
|
18
|
+
this.client.close();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.TypedClient = TypedClient;
|
|
22
|
+
//# sourceMappingURL=typed-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typed-client.js","sourceRoot":"","sources":["../../src/client/typed-client.ts"],"names":[],"mappings":";;;AAUA,MAAa,WAAW;IACtB,YAA6B,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAEpD,IAAI,CACF,OAAU,EACV,OAAgC;QAEhC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAA2B,OAAO,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,CACF,OAAU,EACV,OAAgC;QAEhC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF;AAxBD,kCAwBC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TNEST_CLIENT_PREFIX = exports.TNEST_OPTIONS = void 0;
|
|
4
|
+
exports.getClientToken = getClientToken;
|
|
5
|
+
exports.TNEST_OPTIONS = Symbol('TNEST_OPTIONS');
|
|
6
|
+
exports.TNEST_CLIENT_PREFIX = 'TNEST_CLIENT_';
|
|
7
|
+
function getClientToken(name) {
|
|
8
|
+
return `${exports.TNEST_CLIENT_PREFIX}${name}`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAGA,wCAEC;AALY,QAAA,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AACxC,QAAA,mBAAmB,GAAG,eAAe,CAAC;AAEnD,SAAgB,cAAc,CAAC,IAAY;IACzC,OAAO,GAAG,2BAAmB,GAAG,IAAI,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/contracts/command.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command } from './command';
|
|
2
|
+
import type { Event } from './event';
|
|
3
|
+
import type { Query } from './query';
|
|
4
|
+
import type { ContractRegistry } from './utility-types';
|
|
5
|
+
export declare function command<TPayload = void, TResponse = void>(): Command<string, TPayload, TResponse>;
|
|
6
|
+
export declare function event<TPayload = void>(): Event<string, TPayload>;
|
|
7
|
+
export declare function query<TPayload = void, TResponse = unknown>(): Query<string, TPayload, TResponse>;
|
|
8
|
+
type InferRegistry<T extends Record<string, any>> = {
|
|
9
|
+
[K in keyof T & string]: T[K] extends Command<any, infer P, infer R> ? Command<K, P, R> : T[K] extends Event<any, infer P> ? Event<K, P> : T[K] extends Query<any, infer P, infer R> ? Query<K, P, R> : never;
|
|
10
|
+
};
|
|
11
|
+
export declare function defineRegistry<T extends Record<string, any>>(contracts: T): InferRegistry<T> & ContractRegistry;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = command;
|
|
4
|
+
exports.event = event;
|
|
5
|
+
exports.query = query;
|
|
6
|
+
exports.defineRegistry = defineRegistry;
|
|
7
|
+
function command() {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
function event() {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
function query() {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
function defineRegistry(contracts) {
|
|
17
|
+
return contracts;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=define-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-helpers.js","sourceRoot":"","sources":["../../src/contracts/define-helpers.ts"],"names":[],"mappings":";;AAKA,0BAEC;AAED,sBAEC;AAED,sBAEC;AAUD,wCAIC;AAxBD,SAAgB,OAAO;IACrB,OAAO,SAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,KAAK;IACnB,OAAO,SAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,KAAK;IACnB,OAAO,SAAgB,CAAC;AAC1B,CAAC;AAUD,SAAgB,cAAc,CAC5B,SAAY;IAEZ,OAAO,SAAgB,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/contracts/event.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { Command } from './command';
|
|
2
|
+
export type { Event } from './event';
|
|
3
|
+
export type { Query } from './query';
|
|
4
|
+
export type { ValidateRegistry } from './registry';
|
|
5
|
+
export { command, event, query, defineRegistry } from './define-helpers';
|
|
6
|
+
export type { AnyContract, PatternOf, PayloadOf, ResponseOf, ContractRegistry, CommandsOf, EventsOf, QueriesOf, CommandPatterns, EventPatterns, QueryPatterns, SendablePatterns, } from './utility-types';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defineRegistry = exports.query = exports.event = exports.command = void 0;
|
|
4
|
+
var define_helpers_1 = require("./define-helpers");
|
|
5
|
+
Object.defineProperty(exports, "command", { enumerable: true, get: function () { return define_helpers_1.command; } });
|
|
6
|
+
Object.defineProperty(exports, "event", { enumerable: true, get: function () { return define_helpers_1.event; } });
|
|
7
|
+
Object.defineProperty(exports, "query", { enumerable: true, get: function () { return define_helpers_1.query; } });
|
|
8
|
+
Object.defineProperty(exports, "defineRegistry", { enumerable: true, get: function () { return define_helpers_1.defineRegistry; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contracts/index.ts"],"names":[],"mappings":";;;AAIA,mDAAyE;AAAhE,yGAAA,OAAO,OAAA;AAAE,uGAAA,KAAK,OAAA;AAAE,uGAAA,KAAK,OAAA;AAAE,gHAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/contracts/query.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ContractRegistry } from './utility-types';
|
|
2
|
+
export type ValidateRegistry<TRegistry extends ContractRegistry> = {
|
|
3
|
+
[K in keyof TRegistry]: TRegistry[K] extends {
|
|
4
|
+
pattern: infer P;
|
|
5
|
+
} ? P extends K ? TRegistry[K] : {
|
|
6
|
+
error: `Pattern '${P & string}' does not match registry key '${K & string}'`;
|
|
7
|
+
} : never;
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/contracts/registry.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Command } from './command';
|
|
2
|
+
import type { Event } from './event';
|
|
3
|
+
import type { Query } from './query';
|
|
4
|
+
export type AnyContract = Command<string, any, any> | Event<string, any> | Query<string, any, any>;
|
|
5
|
+
export type PatternOf<C extends AnyContract> = C['pattern'];
|
|
6
|
+
export type PayloadOf<C extends AnyContract> = C['payload'];
|
|
7
|
+
export type ResponseOf<C extends AnyContract> = C extends Command<any, any, infer R> ? R : C extends Query<any, any, infer R> ? R : C extends Event ? undefined : never;
|
|
8
|
+
export type ContractRegistry = Record<string, AnyContract>;
|
|
9
|
+
export type CommandsOf<TRegistry extends ContractRegistry> = {
|
|
10
|
+
[K in keyof TRegistry as TRegistry[K] extends Command<any, any, any> ? K : never]: TRegistry[K];
|
|
11
|
+
};
|
|
12
|
+
export type EventsOf<TRegistry extends ContractRegistry> = {
|
|
13
|
+
[K in keyof TRegistry as TRegistry[K] extends Event<any, any> ? K : never]: TRegistry[K];
|
|
14
|
+
};
|
|
15
|
+
export type QueriesOf<TRegistry extends ContractRegistry> = {
|
|
16
|
+
[K in keyof TRegistry as TRegistry[K] extends Query<any, any, any> ? K : never]: TRegistry[K];
|
|
17
|
+
};
|
|
18
|
+
export type CommandPatterns<TRegistry extends ContractRegistry> = keyof CommandsOf<TRegistry> & string;
|
|
19
|
+
export type EventPatterns<TRegistry extends ContractRegistry> = keyof EventsOf<TRegistry> & string;
|
|
20
|
+
export type QueryPatterns<TRegistry extends ContractRegistry> = keyof QueriesOf<TRegistry> & string;
|
|
21
|
+
export type SendablePatterns<TRegistry extends ContractRegistry> = CommandPatterns<TRegistry> | QueryPatterns<TRegistry>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utility-types.js","sourceRoot":"","sources":["../../src/contracts/utility-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import type { ContractRegistry, CommandPatterns, EventPatterns, QueryPatterns, PayloadOf, ResponseOf } from '../contracts';
|
|
3
|
+
export type TypedMessageHandler<TRegistry extends ContractRegistry, P extends CommandPatterns<TRegistry> | QueryPatterns<TRegistry>> = (payload: PayloadOf<TRegistry[P]>) => ResponseOf<TRegistry[P]> | Promise<ResponseOf<TRegistry[P]>> | Observable<ResponseOf<TRegistry[P]>>;
|
|
4
|
+
export type TypedEventHandler<TRegistry extends ContractRegistry, P extends EventPatterns<TRegistry>> = (payload: PayloadOf<TRegistry[P]>) => void | Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-types.js","sourceRoot":"","sources":["../../src/handlers/handler-types.ts"],"names":[],"mappings":""}
|