@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.
Files changed (86) hide show
  1. package/README.md +357 -0
  2. package/dist/client/index.d.ts +2 -0
  3. package/dist/client/index.js +8 -0
  4. package/dist/client/index.js.map +1 -0
  5. package/dist/client/typed-client-factory.d.ts +6 -0
  6. package/dist/client/typed-client-factory.js +25 -0
  7. package/dist/client/typed-client-factory.js.map +1 -0
  8. package/dist/client/typed-client.d.ts +11 -0
  9. package/dist/client/typed-client.js +22 -0
  10. package/dist/client/typed-client.js.map +1 -0
  11. package/dist/constants.d.ts +3 -0
  12. package/dist/constants.js +10 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/contracts/command.d.ts +6 -0
  15. package/dist/contracts/command.js +3 -0
  16. package/dist/contracts/command.js.map +1 -0
  17. package/dist/contracts/define-helpers.d.ts +12 -0
  18. package/dist/contracts/define-helpers.js +19 -0
  19. package/dist/contracts/define-helpers.js.map +1 -0
  20. package/dist/contracts/event.d.ts +5 -0
  21. package/dist/contracts/event.js +3 -0
  22. package/dist/contracts/event.js.map +1 -0
  23. package/dist/contracts/index.d.ts +6 -0
  24. package/dist/contracts/index.js +9 -0
  25. package/dist/contracts/index.js.map +1 -0
  26. package/dist/contracts/query.d.ts +6 -0
  27. package/dist/contracts/query.js +3 -0
  28. package/dist/contracts/query.js.map +1 -0
  29. package/dist/contracts/registry.d.ts +8 -0
  30. package/dist/contracts/registry.js +3 -0
  31. package/dist/contracts/registry.js.map +1 -0
  32. package/dist/contracts/utility-types.d.ts +21 -0
  33. package/dist/contracts/utility-types.js +3 -0
  34. package/dist/contracts/utility-types.js.map +1 -0
  35. package/dist/handlers/handler-types.d.ts +4 -0
  36. package/dist/handlers/handler-types.js +3 -0
  37. package/dist/handlers/handler-types.js.map +1 -0
  38. package/dist/handlers/index.d.ts +3 -0
  39. package/dist/handlers/index.js +8 -0
  40. package/dist/handlers/index.js.map +1 -0
  41. package/dist/handlers/typed-event-pattern.decorator.d.ts +2 -0
  42. package/dist/handlers/typed-event-pattern.decorator.js +8 -0
  43. package/dist/handlers/typed-event-pattern.decorator.js.map +1 -0
  44. package/dist/handlers/typed-message-pattern.decorator.d.ts +2 -0
  45. package/dist/handlers/typed-message-pattern.decorator.js +8 -0
  46. package/dist/handlers/typed-message-pattern.decorator.js.map +1 -0
  47. package/dist/index.d.ts +16 -1
  48. package/dist/index.js +29 -3
  49. package/dist/index.js.map +1 -1
  50. package/dist/interfaces/index.d.ts +1 -0
  51. package/dist/interfaces/index.js +3 -0
  52. package/dist/interfaces/index.js.map +1 -0
  53. package/dist/interfaces/module-options.d.ts +18 -0
  54. package/dist/interfaces/module-options.js +3 -0
  55. package/dist/interfaces/module-options.js.map +1 -0
  56. package/dist/serialization/default-serializer.d.ts +5 -0
  57. package/dist/serialization/default-serializer.js +23 -0
  58. package/dist/serialization/default-serializer.js.map +1 -0
  59. package/dist/serialization/index.d.ts +3 -0
  60. package/dist/serialization/index.js +9 -0
  61. package/dist/serialization/index.js.map +1 -0
  62. package/dist/serialization/serializer.interface.d.ts +8 -0
  63. package/dist/serialization/serializer.interface.js +6 -0
  64. package/dist/serialization/serializer.interface.js.map +1 -0
  65. package/dist/testing/index.d.ts +2 -0
  66. package/dist/testing/index.js +8 -0
  67. package/dist/testing/index.js.map +1 -0
  68. package/dist/testing/mock-typed-client.d.ts +20 -0
  69. package/dist/testing/mock-typed-client.js +36 -0
  70. package/dist/testing/mock-typed-client.js.map +1 -0
  71. package/dist/testing/test-contract-module.d.ts +10 -0
  72. package/dist/testing/test-contract-module.js +31 -0
  73. package/dist/testing/test-contract-module.js.map +1 -0
  74. package/dist/tnest.module.d.ts +6 -0
  75. package/dist/tnest.module.js +77 -7
  76. package/dist/tnest.module.js.map +1 -1
  77. package/dist/validation/index.d.ts +3 -0
  78. package/dist/validation/index.js +8 -0
  79. package/dist/validation/index.js.map +1 -0
  80. package/dist/validation/validate-contract.decorator.d.ts +1 -0
  81. package/dist/validation/validate-contract.decorator.js +21 -0
  82. package/dist/validation/validate-contract.decorator.js.map +1 -0
  83. package/dist/validation/validator.interface.d.ts +4 -0
  84. package/dist/validation/validator.interface.js +5 -0
  85. package/dist/validation/validator.interface.js.map +1 -0
  86. 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,2 @@
1
+ export { TypedClient } from './typed-client';
2
+ export { TypedClientFactory } from './typed-client-factory';
@@ -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,3 @@
1
+ export declare const TNEST_OPTIONS: unique symbol;
2
+ export declare const TNEST_CLIENT_PREFIX = "TNEST_CLIENT_";
3
+ export declare function getClientToken(name: string): string;
@@ -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,6 @@
1
+ export interface Command<TPattern extends string = string, TPayload = unknown, TResponse = void> {
2
+ readonly __type: 'command';
3
+ readonly pattern: TPattern;
4
+ readonly payload: TPayload;
5
+ readonly response: TResponse;
6
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=command.js.map
@@ -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,5 @@
1
+ export interface Event<TPattern extends string = string, TPayload = unknown> {
2
+ readonly __type: 'event';
3
+ readonly pattern: TPattern;
4
+ readonly payload: TPayload;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=event.js.map
@@ -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,6 @@
1
+ export interface Query<TPattern extends string = string, TPayload = unknown, TResponse = unknown> {
2
+ readonly __type: 'query';
3
+ readonly pattern: TPattern;
4
+ readonly payload: TPayload;
5
+ readonly response: TResponse;
6
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=query.js.map
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=registry.js.map
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=utility-types.js.map
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=handler-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-types.js","sourceRoot":"","sources":["../../src/handlers/handler-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export { TypedMessagePattern } from './typed-message-pattern.decorator';
2
+ export { TypedEventPattern } from './typed-event-pattern.decorator';
3
+ export type { TypedMessageHandler, TypedEventHandler } from './handler-types';