@jdevel/tnest 0.0.2 → 0.0.4
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 +260 -86
- package/dist/__tests__/constants.spec.d.ts +1 -0
- package/dist/__tests__/constants.spec.js +21 -0
- package/dist/__tests__/constants.spec.js.map +1 -0
- package/dist/__tests__/tnest-module.spec.d.ts +1 -0
- package/dist/__tests__/tnest-module.spec.js +88 -0
- package/dist/__tests__/tnest-module.spec.js.map +1 -0
- package/dist/client/__tests__/typed-client-factory.spec.d.ts +1 -0
- package/dist/client/__tests__/typed-client-factory.spec.js +35 -0
- package/dist/client/__tests__/typed-client-factory.spec.js.map +1 -0
- package/dist/client/__tests__/typed-client-types.spec.d.ts +1 -0
- package/dist/client/__tests__/typed-client-types.spec.js +18 -0
- package/dist/client/__tests__/typed-client-types.spec.js.map +1 -0
- package/dist/client/__tests__/typed-client.spec.d.ts +1 -0
- package/dist/client/__tests__/typed-client.spec.js +59 -0
- package/dist/client/__tests__/typed-client.spec.js.map +1 -0
- package/dist/contracts/__tests__/contract-types.spec.d.ts +1 -0
- package/dist/contracts/__tests__/contract-types.spec.js +91 -0
- package/dist/contracts/__tests__/contract-types.spec.js.map +1 -0
- package/dist/contracts/__tests__/define-helpers.spec.d.ts +1 -0
- package/dist/contracts/__tests__/define-helpers.spec.js +52 -0
- package/dist/contracts/__tests__/define-helpers.spec.js.map +1 -0
- package/dist/contracts/define-helpers.js.map +1 -1
- package/dist/handlers/__tests__/handler-types.spec.d.ts +1 -0
- package/dist/handlers/__tests__/handler-types.spec.js +17 -0
- package/dist/handlers/__tests__/handler-types.spec.js.map +1 -0
- package/dist/handlers/__tests__/typed-event-pattern.spec.d.ts +1 -0
- package/dist/handlers/__tests__/typed-event-pattern.spec.js +61 -0
- package/dist/handlers/__tests__/typed-event-pattern.spec.js.map +1 -0
- package/dist/handlers/__tests__/typed-message-pattern.spec.d.ts +1 -0
- package/dist/handlers/__tests__/typed-message-pattern.spec.js +94 -0
- package/dist/handlers/__tests__/typed-message-pattern.spec.js.map +1 -0
- package/dist/handlers/typed-event-pattern.decorator.d.ts +4 -2
- package/dist/handlers/typed-event-pattern.decorator.js.map +1 -1
- package/dist/handlers/typed-message-pattern.decorator.d.ts +5 -2
- package/dist/handlers/typed-message-pattern.decorator.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/module-options.d.ts +1 -0
- package/dist/serialization/__tests__/default-serializer.spec.d.ts +1 -0
- package/dist/serialization/__tests__/default-serializer.spec.js +32 -0
- package/dist/serialization/__tests__/default-serializer.spec.js.map +1 -0
- package/dist/testing/__tests__/mock-typed-client.spec.d.ts +1 -0
- package/dist/testing/__tests__/mock-typed-client.spec.js +70 -0
- package/dist/testing/__tests__/mock-typed-client.spec.js.map +1 -0
- package/dist/testing/__tests__/test-contract-module.spec.d.ts +1 -0
- package/dist/testing/__tests__/test-contract-module.spec.js +30 -0
- package/dist/testing/__tests__/test-contract-module.spec.js.map +1 -0
- package/dist/testing/mock-typed-client.js.map +1 -1
- package/dist/tnest.module.d.ts +1 -0
- package/dist/tnest.module.js +21 -20
- package/dist/tnest.module.js.map +1 -1
- package/dist/validation/__tests__/validate-contract.spec.d.ts +1 -0
- package/dist/validation/__tests__/validate-contract.spec.js +102 -0
- package/dist/validation/__tests__/validate-contract.spec.js.map +1 -0
- package/dist/validation/validate-contract.decorator.js.map +1 -1
- package/package.json +30 -5
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rxjs_1 = require("rxjs");
|
|
4
|
+
const mock_typed_client_1 = require("../mock-typed-client");
|
|
5
|
+
describe('MockTypedClient', () => {
|
|
6
|
+
let mock;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
mock = new mock_typed_client_1.MockTypedClient();
|
|
9
|
+
});
|
|
10
|
+
describe('send()', () => {
|
|
11
|
+
it('records sent messages', () => {
|
|
12
|
+
mock.send('user.create', { name: 'Alice' });
|
|
13
|
+
expect(mock.messages).toHaveLength(1);
|
|
14
|
+
expect(mock.messages[0]).toEqual({
|
|
15
|
+
type: 'send',
|
|
16
|
+
pattern: 'user.create',
|
|
17
|
+
payload: { name: 'Alice' },
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it('returns canned response when set', async () => {
|
|
21
|
+
mock.setResponse('user.create', { id: '42' });
|
|
22
|
+
const result = await (0, rxjs_1.firstValueFrom)(mock.send('user.create', { name: 'Alice' }));
|
|
23
|
+
expect(result).toEqual({ id: '42' });
|
|
24
|
+
});
|
|
25
|
+
it('returns undefined when no response is set', async () => {
|
|
26
|
+
const result = await (0, rxjs_1.firstValueFrom)(mock.send('user.create', { name: 'Alice' }));
|
|
27
|
+
expect(result).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('emit()', () => {
|
|
31
|
+
it('records emitted messages', () => {
|
|
32
|
+
mock.emit('user.created', { userId: '42' });
|
|
33
|
+
expect(mock.messages).toHaveLength(1);
|
|
34
|
+
expect(mock.messages[0]).toEqual({
|
|
35
|
+
type: 'emit',
|
|
36
|
+
pattern: 'user.created',
|
|
37
|
+
payload: { userId: '42' },
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
it('returns Observable<undefined>', async () => {
|
|
41
|
+
const result = await (0, rxjs_1.firstValueFrom)(mock.emit('user.created', { userId: '42' }));
|
|
42
|
+
expect(result).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('connect()', () => {
|
|
46
|
+
it('resolves immediately', async () => {
|
|
47
|
+
await expect(mock.connect()).resolves.toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('close()', () => {
|
|
51
|
+
it('is a no-op', () => {
|
|
52
|
+
expect(() => mock.close()).not.toThrow();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('reset()', () => {
|
|
56
|
+
it('clears recorded messages', () => {
|
|
57
|
+
mock.send('user.create', { name: 'Alice' });
|
|
58
|
+
mock.emit('user.created', { userId: '42' });
|
|
59
|
+
mock.reset();
|
|
60
|
+
expect(mock.messages).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
it('clears canned responses', async () => {
|
|
63
|
+
mock.setResponse('user.create', { id: '42' });
|
|
64
|
+
mock.reset();
|
|
65
|
+
const result = await (0, rxjs_1.firstValueFrom)(mock.send('user.create', { name: 'Alice' }));
|
|
66
|
+
expect(result).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=mock-typed-client.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-typed-client.spec.js","sourceRoot":"","sources":["../../../src/testing/__tests__/mock-typed-client.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const testing_1 = require("@nestjs/testing");
|
|
4
|
+
const test_contract_module_1 = require("../test-contract-module");
|
|
5
|
+
const mock_typed_client_1 = require("../mock-typed-client");
|
|
6
|
+
const client_1 = require("../../client");
|
|
7
|
+
const constants_1 = require("../../constants");
|
|
8
|
+
describe('TestContractModule', () => {
|
|
9
|
+
it('registers mock clients as injectable by token', async () => {
|
|
10
|
+
const mockClient = new mock_typed_client_1.MockTypedClient();
|
|
11
|
+
const module = await testing_1.Test.createTestingModule({
|
|
12
|
+
imports: [
|
|
13
|
+
test_contract_module_1.TestContractModule.register([
|
|
14
|
+
{ name: 'TEST_SERVICE', mock: mockClient },
|
|
15
|
+
]),
|
|
16
|
+
],
|
|
17
|
+
}).compile();
|
|
18
|
+
const token = (0, constants_1.getClientToken)('TEST_SERVICE');
|
|
19
|
+
const resolved = module.get(token);
|
|
20
|
+
expect(resolved).toBe(mockClient);
|
|
21
|
+
});
|
|
22
|
+
it('provides TypedClientFactory', async () => {
|
|
23
|
+
const module = await testing_1.Test.createTestingModule({
|
|
24
|
+
imports: [test_contract_module_1.TestContractModule.register([])],
|
|
25
|
+
}).compile();
|
|
26
|
+
const factory = module.get(client_1.TypedClientFactory);
|
|
27
|
+
expect(factory).toBeInstanceOf(client_1.TypedClientFactory);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=test-contract-module.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-contract-module.spec.js","sourceRoot":"","sources":["../../../src/testing/__tests__/test-contract-module.spec.ts"],"names":[],"mappings":";;AAAA,6CAAuC;AACvC,kEAA6D;AAC7D,4DAAuD;AACvD,yCAAkD;AAClD,+CAAiD;AAQjD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,UAAU,GAAG,IAAI,mCAAe,EAAgB,CAAC;QAEvD,MAAM,MAAM,GAAG,MAAM,cAAI,CAAC,mBAAmB,CAAC;YAC5C,OAAO,EAAE;gBACP,yCAAkB,CAAC,QAAQ,CAAC;oBAC1B,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAoC,EAAE;iBACrE,CAAC;aACH;SACF,CAAC,CAAC,OAAO,EAAE,CAAC;QAEb,MAAM,KAAK,GAAG,IAAA,0BAAc,EAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAU,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,MAAM,GAAG,MAAM,cAAI,CAAC,mBAAmB,CAAC;YAC5C,OAAO,EAAE,CAAC,yCAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;SAC3C,CAAC,CAAC,OAAO,EAAE,CAAC;QAEb,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,2BAAkB,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,2BAAkB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-typed-client.js","sourceRoot":"","sources":["../../src/testing/mock-typed-client.ts"],"names":[],"mappings":";;;AAAA,+BAA2C;AAgB3C,MAAa,eAAe;IAA5B;
|
|
1
|
+
{"version":3,"file":"mock-typed-client.js","sourceRoot":"","sources":["../../src/testing/mock-typed-client.ts"],"names":[],"mappings":";;;AAAA,+BAA2C;AAgB3C,MAAa,eAAe;IAA5B;QAImB,cAAS,GAAsB,EAAE,CAAC;QAClC,eAAU,GAAG,IAAI,GAAG,EAAmB,CAAC;IA0C3D,CAAC;IAxCC,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,WAAW,CACT,OAAU,EACV,QAAkC;QAElC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CACF,OAAU,EACV,OAAgC;QAEhC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAA6B,CAAC;QAC1E,OAAO,IAAA,SAAE,EAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,CACF,OAAU,EACV,OAAgC;QAEhC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,OAAO,IAAA,SAAE,EAAC,SAAS,CAAC,CAAC;IACvB,CAAC;IAED,OAAO;QACL,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK;IAEL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF;AA/CD,0CA+CC"}
|
package/dist/tnest.module.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { TnestModuleOptions, TnestModuleAsyncOptions } from './interfaces';
|
|
|
3
3
|
export declare class TnestModule {
|
|
4
4
|
static forRoot(options?: TnestModuleOptions): DynamicModule;
|
|
5
5
|
static forRootAsync(options: TnestModuleAsyncOptions): DynamicModule;
|
|
6
|
+
private static createAsyncClientProviders;
|
|
6
7
|
private static createClientProviders;
|
|
7
8
|
private static createAsyncProviders;
|
|
8
9
|
}
|
package/dist/tnest.module.js
CHANGED
|
@@ -23,35 +23,33 @@ let TnestModule = TnestModule_1 = class TnestModule {
|
|
|
23
23
|
client_1.TypedClientFactory,
|
|
24
24
|
...clientProviders,
|
|
25
25
|
],
|
|
26
|
-
exports: [
|
|
27
|
-
client_1.TypedClientFactory,
|
|
28
|
-
...clientProviders.map((p) => p.provide),
|
|
29
|
-
],
|
|
26
|
+
exports: [client_1.TypedClientFactory, ...clientProviders.map((p) => p.provide)],
|
|
30
27
|
};
|
|
31
28
|
}
|
|
32
29
|
static forRootAsync(options) {
|
|
33
30
|
const asyncProviders = TnestModule_1.createAsyncProviders(options);
|
|
34
|
-
const clientProviders = [
|
|
35
|
-
{
|
|
36
|
-
provide: 'TNEST_CLIENT_PROVIDERS',
|
|
37
|
-
useFactory: (tnestOptions) => {
|
|
38
|
-
return TnestModule_1.createClientProviders(tnestOptions);
|
|
39
|
-
},
|
|
40
|
-
inject: [constants_1.TNEST_OPTIONS],
|
|
41
|
-
},
|
|
42
|
-
];
|
|
31
|
+
const clientProviders = TnestModule_1.createAsyncClientProviders(options.clientNames ?? []);
|
|
43
32
|
return {
|
|
44
33
|
module: TnestModule_1,
|
|
45
34
|
global: true,
|
|
46
35
|
imports: options.imports ?? [],
|
|
47
|
-
providers: [
|
|
48
|
-
|
|
49
|
-
client_1.TypedClientFactory,
|
|
50
|
-
...clientProviders,
|
|
51
|
-
],
|
|
52
|
-
exports: [client_1.TypedClientFactory, constants_1.TNEST_OPTIONS],
|
|
36
|
+
providers: [...asyncProviders, client_1.TypedClientFactory, ...clientProviders],
|
|
37
|
+
exports: [client_1.TypedClientFactory, constants_1.TNEST_OPTIONS, ...clientProviders.map((p) => p.provide)],
|
|
53
38
|
};
|
|
54
39
|
}
|
|
40
|
+
static createAsyncClientProviders(clientNames) {
|
|
41
|
+
return clientNames.map((name) => ({
|
|
42
|
+
provide: (0, constants_1.getClientToken)(name),
|
|
43
|
+
useFactory: (tnestOptions) => {
|
|
44
|
+
const clientDef = tnestOptions.clients?.find((c) => c.name === name);
|
|
45
|
+
if (!clientDef) {
|
|
46
|
+
throw new Error(`TnestModule: client "${name}" was declared in clientNames but not found in resolved options.clients`);
|
|
47
|
+
}
|
|
48
|
+
return microservices_1.ClientProxyFactory.create(clientDef.options);
|
|
49
|
+
},
|
|
50
|
+
inject: [constants_1.TNEST_OPTIONS],
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
55
53
|
static createClientProviders(options) {
|
|
56
54
|
if (!options.clients?.length)
|
|
57
55
|
return [];
|
|
@@ -70,7 +68,10 @@ let TnestModule = TnestModule_1 = class TnestModule {
|
|
|
70
68
|
},
|
|
71
69
|
];
|
|
72
70
|
}
|
|
73
|
-
const useClass =
|
|
71
|
+
const useClass = options.useClass ?? options.useExisting;
|
|
72
|
+
if (!useClass) {
|
|
73
|
+
throw new Error('TnestModule.forRootAsync() requires one of: useFactory, useClass, or useExisting');
|
|
74
|
+
}
|
|
74
75
|
const providers = [
|
|
75
76
|
{
|
|
76
77
|
provide: constants_1.TNEST_OPTIONS,
|
package/dist/tnest.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tnest.module.js","sourceRoot":"","sources":["../src/tnest.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"tnest.module.js","sourceRoot":"","sources":["../src/tnest.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
require("reflect-metadata");
|
|
13
|
+
const validate_contract_decorator_1 = require("../validate-contract.decorator");
|
|
14
|
+
describe('ValidateContract', () => {
|
|
15
|
+
it('calls validator.validate() before the handler', async () => {
|
|
16
|
+
const validator = {
|
|
17
|
+
validate: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
class TestHandler {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.__contractValidator = validator;
|
|
22
|
+
}
|
|
23
|
+
handle(payload) {
|
|
24
|
+
return `processed: ${String(payload)}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
__decorate([
|
|
28
|
+
(0, validate_contract_decorator_1.ValidateContract)(),
|
|
29
|
+
__metadata("design:type", Function),
|
|
30
|
+
__metadata("design:paramtypes", [Object]),
|
|
31
|
+
__metadata("design:returntype", String)
|
|
32
|
+
], TestHandler.prototype, "handle", null);
|
|
33
|
+
const handler = new TestHandler();
|
|
34
|
+
const result = await handler.handle('test-data');
|
|
35
|
+
expect(validator.validate).toHaveBeenCalledWith('test-data');
|
|
36
|
+
expect(result).toBe('processed: test-data');
|
|
37
|
+
});
|
|
38
|
+
it('runs handler without validation when no validator is set', async () => {
|
|
39
|
+
class TestHandler {
|
|
40
|
+
constructor() {
|
|
41
|
+
this.__contractValidator = undefined;
|
|
42
|
+
}
|
|
43
|
+
handle(payload) {
|
|
44
|
+
return `processed: ${String(payload)}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, validate_contract_decorator_1.ValidateContract)(),
|
|
49
|
+
__metadata("design:type", Function),
|
|
50
|
+
__metadata("design:paramtypes", [Object]),
|
|
51
|
+
__metadata("design:returntype", String)
|
|
52
|
+
], TestHandler.prototype, "handle", null);
|
|
53
|
+
const handler = new TestHandler();
|
|
54
|
+
const result = await handler.handle('test-data');
|
|
55
|
+
expect(result).toBe('processed: test-data');
|
|
56
|
+
});
|
|
57
|
+
it('propagates validation errors', async () => {
|
|
58
|
+
const validator = {
|
|
59
|
+
validate: jest.fn().mockRejectedValue(new Error('Validation failed')),
|
|
60
|
+
};
|
|
61
|
+
class TestHandler {
|
|
62
|
+
constructor() {
|
|
63
|
+
this.__contractValidator = validator;
|
|
64
|
+
}
|
|
65
|
+
handle(payload) {
|
|
66
|
+
return `processed: ${String(payload)}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
__decorate([
|
|
70
|
+
(0, validate_contract_decorator_1.ValidateContract)(),
|
|
71
|
+
__metadata("design:type", Function),
|
|
72
|
+
__metadata("design:paramtypes", [Object]),
|
|
73
|
+
__metadata("design:returntype", String)
|
|
74
|
+
], TestHandler.prototype, "handle", null);
|
|
75
|
+
const handler = new TestHandler();
|
|
76
|
+
await expect(handler.handle('bad-data')).rejects.toThrow('Validation failed');
|
|
77
|
+
});
|
|
78
|
+
it('supports synchronous validators', async () => {
|
|
79
|
+
const validator = {
|
|
80
|
+
validate: jest.fn(),
|
|
81
|
+
};
|
|
82
|
+
class TestHandler {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.__contractValidator = validator;
|
|
85
|
+
}
|
|
86
|
+
handle(payload) {
|
|
87
|
+
return `processed: ${String(payload)}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
__decorate([
|
|
91
|
+
(0, validate_contract_decorator_1.ValidateContract)(),
|
|
92
|
+
__metadata("design:type", Function),
|
|
93
|
+
__metadata("design:paramtypes", [Object]),
|
|
94
|
+
__metadata("design:returntype", String)
|
|
95
|
+
], TestHandler.prototype, "handle", null);
|
|
96
|
+
const handler = new TestHandler();
|
|
97
|
+
const result = await handler.handle('sync-data');
|
|
98
|
+
expect(validator.validate).toHaveBeenCalledWith('sync-data');
|
|
99
|
+
expect(result).toBe('processed: sync-data');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=validate-contract.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-contract.spec.js","sourceRoot":"","sources":["../../../src/validation/__tests__/validate-contract.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-contract.decorator.js","sourceRoot":"","sources":["../../src/validation/validate-contract.decorator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"validate-contract.decorator.js","sourceRoot":"","sources":["../../src/validation/validate-contract.decorator.ts"],"names":[],"mappings":";;AAKA,4CAsBC;AA3BD,2CAAwC;AACxC,+DAAmF;AAInF,SAAgB,gBAAgB;IAC9B,MAAM,eAAe,GAAG,IAAA,eAAM,EAAC,wCAAkB,CAAC,CAAC;IAEnD,OAAO,CACL,MAAc,EACd,WAA4B,EAC5B,UAAwC,EACxC,EAAE;QACF,eAAe,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAE/C,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC;QAExC,UAAU,CAAC,KAAK,GAAG,KAAK,WAAsB,OAAgB,EAAE,GAAG,IAAe;YAChF,MAAM,SAAS,GAAkC,IAAI,CAAC,mBAAmB,CAAC;YAC1E,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpC,CAAC;YACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACrD,CAAC,CAAC;QAEF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jdevel/tnest",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "Type-safe communication between NestJS microservices via shared contracts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "./node_modules/.bin/tsc",
|
|
12
|
-
"lint": "eslint src/",
|
|
13
|
-
"lint:fix": "eslint src/ --fix",
|
|
14
|
-
"
|
|
12
|
+
"lint": "./node_modules/.bin/eslint src/",
|
|
13
|
+
"lint:fix": "./node_modules/.bin/eslint src/ --fix",
|
|
14
|
+
"test": "./node_modules/.bin/jest",
|
|
15
|
+
"test:watch": "./node_modules/.bin/jest --watch",
|
|
16
|
+
"test:cov": "./node_modules/.bin/jest --coverage",
|
|
17
|
+
"format": "./node_modules/.bin/prettier --write .",
|
|
18
|
+
"format:check": "./node_modules/.bin/prettier --check .",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"prepare": "./node_modules/.bin/husky"
|
|
15
21
|
},
|
|
16
22
|
"peerDependencies": {
|
|
17
23
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
@@ -23,11 +29,30 @@
|
|
|
23
29
|
"@eslint/js": "^10.0.1",
|
|
24
30
|
"@nestjs/common": "^11.0.0",
|
|
25
31
|
"@nestjs/microservices": "^11.1.17",
|
|
32
|
+
"@nestjs/testing": "^11.1.17",
|
|
33
|
+
"@types/jest": "^30.0.0",
|
|
26
34
|
"eslint": "^10.1.0",
|
|
35
|
+
"eslint-config-prettier": "^10.1.8",
|
|
36
|
+
"expect-type": "^1.3.0",
|
|
37
|
+
"husky": "^9.1.7",
|
|
38
|
+
"jest": "^30.3.0",
|
|
39
|
+
"prettier": "^3.8.1",
|
|
27
40
|
"reflect-metadata": "^0.2.0",
|
|
28
41
|
"rxjs": "^7.8.1",
|
|
42
|
+
"ts-jest": "^29.4.6",
|
|
29
43
|
"typescript": "^5.7.0",
|
|
30
44
|
"typescript-eslint": "^8.57.2"
|
|
31
45
|
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"nestjs",
|
|
48
|
+
"microservices",
|
|
49
|
+
"type-safe",
|
|
50
|
+
"contracts",
|
|
51
|
+
"typescript",
|
|
52
|
+
"messaging"
|
|
53
|
+
],
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18"
|
|
56
|
+
},
|
|
32
57
|
"license": "MIT"
|
|
33
58
|
}
|