@rsdk/nats.common 5.3.0-next.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/client/client.config.d.ts +6 -0
  3. package/dist/client/client.config.js +36 -0
  4. package/dist/client/client.config.js.map +1 -0
  5. package/dist/client/client.constants.d.ts +2 -0
  6. package/dist/client/client.constants.js +6 -0
  7. package/dist/client/client.constants.js.map +1 -0
  8. package/dist/client/client.decorators.d.ts +2 -0
  9. package/dist/client/client.decorators.js +10 -0
  10. package/dist/client/client.decorators.js.map +1 -0
  11. package/dist/client/client.metadata.d.ts +21 -0
  12. package/dist/client/client.metadata.js +10 -0
  13. package/dist/client/client.metadata.js.map +1 -0
  14. package/dist/client/client.module.d.ts +2 -0
  15. package/dist/client/client.module.js +27 -0
  16. package/dist/client/client.module.js.map +1 -0
  17. package/dist/client/client.provider.d.ts +2 -0
  18. package/dist/client/client.provider.js +18 -0
  19. package/dist/client/client.provider.js.map +1 -0
  20. package/dist/client/producer.provider.d.ts +4 -0
  21. package/dist/client/producer.provider.js +12 -0
  22. package/dist/client/producer.provider.js.map +1 -0
  23. package/dist/client/topics.service.d.ts +8 -0
  24. package/dist/client/topics.service.js +35 -0
  25. package/dist/client/topics.service.js.map +1 -0
  26. package/dist/event.codec.d.ts +22 -0
  27. package/dist/event.codec.js +32 -0
  28. package/dist/event.codec.js.map +1 -0
  29. package/dist/event.type.d.ts +23 -0
  30. package/dist/event.type.js +18 -0
  31. package/dist/event.type.js.map +1 -0
  32. package/dist/exceptions/exception.handler.d.ts +1 -0
  33. package/dist/exceptions/exception.handler.js +9 -0
  34. package/dist/exceptions/exception.handler.js.map +1 -0
  35. package/dist/exceptions/missing-topics.exception.d.ts +6 -0
  36. package/dist/exceptions/missing-topics.exception.js +19 -0
  37. package/dist/exceptions/missing-topics.exception.js.map +1 -0
  38. package/dist/exceptions/payload-format.exception.d.ts +5 -0
  39. package/dist/exceptions/payload-format.exception.js +11 -0
  40. package/dist/exceptions/payload-format.exception.js.map +1 -0
  41. package/dist/exceptions/unknown-nats.exception.d.ts +4 -0
  42. package/dist/exceptions/unknown-nats.exception.js +17 -0
  43. package/dist/exceptions/unknown-nats.exception.js.map +1 -0
  44. package/dist/index.d.ts +8 -0
  45. package/dist/index.js +25 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/payload.format.d.ts +31 -0
  48. package/dist/payload.format.js +46 -0
  49. package/dist/payload.format.js.map +1 -0
  50. package/package.json +30 -0
  51. package/src/client/client.config.ts +24 -0
  52. package/src/client/client.constants.ts +2 -0
  53. package/src/client/client.decorators.ts +12 -0
  54. package/src/client/client.metadata.ts +30 -0
  55. package/src/client/client.module.ts +15 -0
  56. package/src/client/client.provider.ts +21 -0
  57. package/src/client/producer.provider.ts +17 -0
  58. package/src/client/topics.service.ts +21 -0
  59. package/src/event.codec.ts +37 -0
  60. package/src/event.type.ts +38 -0
  61. package/src/exceptions/exception.handler.ts +9 -0
  62. package/src/exceptions/missing-topics.exception.ts +17 -0
  63. package/src/exceptions/payload-format.exception.ts +10 -0
  64. package/src/exceptions/unknown-nats.exception.ts +13 -0
  65. package/src/index.ts +27 -0
  66. package/src/payload.format.ts +51 -0
  67. package/tsconfig.build.json +12 -0
  68. package/tsconfig.json +7 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [5.3.0-next.4](https://github.com/R-Vision/rsdk/compare/v5.3.0-next.3...v5.3.0-next.4) (2024-11-05)
7
+
8
+ ### Features
9
+
10
+ * **nats.producer:** direct nats producer alpha implementation ([#301](https://github.com/R-Vision/rsdk/issues/301)) ([d173b51](https://github.com/R-Vision/rsdk/commit/d173b51c664c718a214cdc695708cfdd40fc4dcb))
@@ -0,0 +1,6 @@
1
+ import { Config } from '@rsdk/core';
2
+ export declare const NatsConfigInstance: unique symbol;
3
+ export declare class DefaultNatsConfig extends Config {
4
+ servers: string[];
5
+ debug: boolean;
6
+ }
@@ -0,0 +1,36 @@
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
+ exports.DefaultNatsConfig = exports.NatsConfigInstance = void 0;
13
+ const core_1 = require("@rsdk/core");
14
+ exports.NatsConfigInstance = Symbol('NatsConfigInstance');
15
+ let DefaultNatsConfig = class DefaultNatsConfig extends core_1.Config {
16
+ servers;
17
+ debug;
18
+ };
19
+ exports.DefaultNatsConfig = DefaultNatsConfig;
20
+ __decorate([
21
+ (0, core_1.Property)('NATS_SERVERS', new core_1.ArrayParser(new core_1.StringParser()), {
22
+ description: 'NATS server URLs',
23
+ }),
24
+ __metadata("design:type", Array)
25
+ ], DefaultNatsConfig.prototype, "servers", void 0);
26
+ __decorate([
27
+ (0, core_1.Property)('NATS_DEBUG', new core_1.BoolParser(), {
28
+ defaultValue: false,
29
+ description: 'Enable NATS debug',
30
+ }),
31
+ __metadata("design:type", Boolean)
32
+ ], DefaultNatsConfig.prototype, "debug", void 0);
33
+ exports.DefaultNatsConfig = DefaultNatsConfig = __decorate([
34
+ (0, core_1.ConfigSection)()
35
+ ], DefaultNatsConfig);
36
+ //# sourceMappingURL=client.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.config.js","sourceRoot":"","sources":["../../src/client/client.config.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAOoB;AAEP,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAGxD,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,aAAM;IAI3C,OAAO,CAAY;IAMnB,KAAK,CAAW;CACjB,CAAA;AAXY,8CAAiB;AAI5B;IAHC,IAAA,eAAQ,EAAC,cAAc,EAAE,IAAI,kBAAW,CAAC,IAAI,mBAAY,EAAE,CAAC,EAAE;QAC7D,WAAW,EAAE,kBAAkB;KAChC,CAAC;;kDACiB;AAMnB;IAJC,IAAA,eAAQ,EAAC,YAAY,EAAE,IAAI,iBAAU,EAAE,EAAE;QACxC,YAAY,EAAE,KAAK;QACnB,WAAW,EAAE,mBAAmB;KACjC,CAAC;;gDACc;4BAVL,iBAAiB;IAD7B,IAAA,oBAAa,GAAE;GACH,iBAAiB,CAW7B"}
@@ -0,0 +1,2 @@
1
+ export declare const NATS_CLIENT_INJECTION_TOKEN: unique symbol;
2
+ export declare const NATS_PRODUCER_INJECTION_TOKEN: unique symbol;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NATS_PRODUCER_INJECTION_TOKEN = exports.NATS_CLIENT_INJECTION_TOKEN = void 0;
4
+ exports.NATS_CLIENT_INJECTION_TOKEN = Symbol('NatsClient');
5
+ exports.NATS_PRODUCER_INJECTION_TOKEN = Symbol('NatsProducer');
6
+ //# sourceMappingURL=client.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.constants.js","sourceRoot":"","sources":["../../src/client/client.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,2BAA2B,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AACnD,QAAA,6BAA6B,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const InjectNatsClient: () => ParameterDecorator;
2
+ export declare const InjectNatsProducer: () => ParameterDecorator;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InjectNatsProducer = exports.InjectNatsClient = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const client_constants_1 = require("./client.constants");
6
+ const InjectNatsClient = () => (0, common_1.Inject)(client_constants_1.NATS_CLIENT_INJECTION_TOKEN);
7
+ exports.InjectNatsClient = InjectNatsClient;
8
+ const InjectNatsProducer = () => (0, common_1.Inject)(client_constants_1.NATS_PRODUCER_INJECTION_TOKEN);
9
+ exports.InjectNatsProducer = InjectNatsProducer;
10
+ //# sourceMappingURL=client.decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.decorators.js","sourceRoot":"","sources":["../../src/client/client.decorators.ts"],"names":[],"mappings":";;;AAAA,2CAAwC;AAExC,yDAG4B;AAErB,MAAM,gBAAgB,GAAG,GAAuB,EAAE,CACvD,IAAA,eAAM,EAAC,8CAA2B,CAAC,CAAC;AADzB,QAAA,gBAAgB,oBACS;AAE/B,MAAM,kBAAkB,GAAG,GAAuB,EAAE,CACzD,IAAA,eAAM,EAAC,gDAA6B,CAAC,CAAC;AAD3B,QAAA,kBAAkB,sBACS"}
@@ -0,0 +1,21 @@
1
+ import type { EventType } from '../event.type';
2
+ export declare enum TopicType {
3
+ PRODUCE = 0
4
+ }
5
+ /**
6
+ * TODO: Здесь надо разбираться с неймингом. Потому что хрен
7
+ * поймёшь сейчас, что это за типы
8
+ */
9
+ export type NatsTopicMetadataByTopic = {
10
+ type: TopicType;
11
+ topicName: string;
12
+ };
13
+ export type NatsTopicMetadataByEventType = {
14
+ type: TopicType;
15
+ topicName: string;
16
+ group: string;
17
+ partitionKeyField: string | null;
18
+ eventType?: Pick<EventType, '$type' | '$group' | '$partitionKeyField'>;
19
+ };
20
+ export type NatsTopicMetadata = NatsTopicMetadataByEventType | NatsTopicMetadataByTopic;
21
+ export declare const NATS_TOPIC_RSDK_METADATA_SCOPE = "nats-stream";
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NATS_TOPIC_RSDK_METADATA_SCOPE = exports.TopicType = void 0;
4
+ var TopicType;
5
+ (function (TopicType) {
6
+ // CONSUME,
7
+ TopicType[TopicType["PRODUCE"] = 0] = "PRODUCE";
8
+ })(TopicType || (exports.TopicType = TopicType = {}));
9
+ exports.NATS_TOPIC_RSDK_METADATA_SCOPE = 'nats-stream';
10
+ //# sourceMappingURL=client.metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.metadata.js","sourceRoot":"","sources":["../../src/client/client.metadata.ts"],"names":[],"mappings":";;;AAEA,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,WAAW;IACX,+CAAO,CAAA;AACT,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB;AAwBY,QAAA,8BAA8B,GAAG,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare class NatsClientModule {
2
+ }
@@ -0,0 +1,27 @@
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.NatsClientModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const core_1 = require("@rsdk/core");
12
+ const client_config_1 = require("./client.config");
13
+ const client_provider_1 = require("./client.provider");
14
+ const producer_provider_1 = require("./producer.provider");
15
+ const topics_service_1 = require("./topics.service");
16
+ let NatsClientModule = class NatsClientModule {
17
+ };
18
+ exports.NatsClientModule = NatsClientModule;
19
+ exports.NatsClientModule = NatsClientModule = __decorate([
20
+ (0, common_1.Global)(),
21
+ (0, common_1.Module)({
22
+ imports: [core_1.PlatformConfigModule.forFeature(client_config_1.DefaultNatsConfig)],
23
+ providers: [producer_provider_1.natsProducerProvider, client_provider_1.natsProvider, topics_service_1.TopicsService],
24
+ exports: [producer_provider_1.natsProducerProvider, client_provider_1.natsProvider, topics_service_1.TopicsService],
25
+ })
26
+ ], NatsClientModule);
27
+ //# sourceMappingURL=client.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.module.js","sourceRoot":"","sources":["../../src/client/client.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,qCAAkD;AAElD,mDAAoD;AACpD,uDAAiD;AACjD,2DAA2D;AAC3D,qDAAiD;AAQ1C,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAN5B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,2BAAoB,CAAC,UAAU,CAAC,iCAAiB,CAAC,CAAC;QAC7D,SAAS,EAAE,CAAC,wCAAoB,EAAE,8BAAY,EAAE,8BAAa,CAAC;QAC9D,OAAO,EAAE,CAAC,wCAAoB,EAAE,8BAAY,EAAE,8BAAa,CAAC;KAC7D,CAAC;GACW,gBAAgB,CAAG"}
@@ -0,0 +1,2 @@
1
+ import type { FactoryProvider } from '@nestjs/common';
2
+ export declare const natsProvider: FactoryProvider;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.natsProvider = void 0;
4
+ const core_1 = require("@rsdk/core");
5
+ const nats_1 = require("nats");
6
+ const client_config_1 = require("./client.config");
7
+ const client_constants_1 = require("./client.constants");
8
+ exports.natsProvider = {
9
+ inject: [client_config_1.DefaultNatsConfig, core_1.APP_NAME],
10
+ provide: client_constants_1.NATS_CLIENT_INJECTION_TOKEN,
11
+ async useFactory(config, name) {
12
+ return await (0, nats_1.connect)({
13
+ name: `${name}-${process.pid}`,
14
+ ...config,
15
+ });
16
+ },
17
+ };
18
+ //# sourceMappingURL=client.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.provider.js","sourceRoot":"","sources":["../../src/client/client.provider.ts"],"names":[],"mappings":";;;AACA,qCAAsC;AAEtC,+BAA+B;AAE/B,mDAAoD;AACpD,yDAAiE;AAEpD,QAAA,YAAY,GAAoB;IAC3C,MAAM,EAAE,CAAC,iCAAiB,EAAE,eAAQ,CAAC;IACrC,OAAO,EAAE,8CAA2B;IACpC,KAAK,CAAC,UAAU,CACd,MAAyB,EACzB,IAAY;QAEZ,OAAO,MAAM,IAAA,cAAO,EAAC;YACnB,IAAI,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE;YAC9B,GAAG,MAAM;SACV,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FactoryProvider } from '@nestjs/common';
2
+ import type { JetStreamClient } from 'nats';
3
+ export type Producer = JetStreamClient;
4
+ export declare const natsProducerProvider: FactoryProvider;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.natsProducerProvider = void 0;
4
+ const client_constants_1 = require("./client.constants");
5
+ exports.natsProducerProvider = {
6
+ inject: [client_constants_1.NATS_CLIENT_INJECTION_TOKEN],
7
+ provide: client_constants_1.NATS_PRODUCER_INJECTION_TOKEN,
8
+ async useFactory(client) {
9
+ return client.jetstream();
10
+ },
11
+ };
12
+ //# sourceMappingURL=producer.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"producer.provider.js","sourceRoot":"","sources":["../../src/client/producer.provider.ts"],"names":[],"mappings":";;;AAGA,yDAG4B;AAIf,QAAA,oBAAoB,GAAoB;IACnD,MAAM,EAAE,CAAC,8CAA2B,CAAC;IACrC,OAAO,EAAE,gDAA6B;IACtC,KAAK,CAAC,UAAU,CAAC,MAAsB;QACrC,OAAO,MAAM,CAAC,SAAS,EAAE,CAAC;IAC5B,CAAC;CACF,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { RsdkMetadataProvider } from '@rsdk/metadata';
2
+ import type { TopicType } from './client.metadata';
3
+ export declare class TopicsService {
4
+ private readonly provider;
5
+ constructor(provider: RsdkMetadataProvider);
6
+ getTopics(type: TopicType): string[];
7
+ private getResources;
8
+ }
@@ -0,0 +1,35 @@
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
+ exports.TopicsService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const metadata_1 = require("@rsdk/metadata");
15
+ const client_metadata_1 = require("./client.metadata");
16
+ let TopicsService = class TopicsService {
17
+ provider;
18
+ constructor(provider) {
19
+ this.provider = provider;
20
+ }
21
+ getTopics(type) {
22
+ return this.getResources()
23
+ .filter(({ value }) => value.type === type)
24
+ .map(({ value }) => value.topicName);
25
+ }
26
+ getResources() {
27
+ return this.provider.get(client_metadata_1.NATS_TOPIC_RSDK_METADATA_SCOPE);
28
+ }
29
+ };
30
+ exports.TopicsService = TopicsService;
31
+ exports.TopicsService = TopicsService = __decorate([
32
+ (0, common_1.Injectable)(),
33
+ __metadata("design:paramtypes", [metadata_1.RsdkMetadataProvider])
34
+ ], TopicsService);
35
+ //# sourceMappingURL=topics.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topics.service.js","sourceRoot":"","sources":["../../src/client/topics.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,6CAAsD;AAGtD,uDAAmE;AAG5D,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,QAA8B;QAA9B,aAAQ,GAAR,QAAQ,CAAsB;IAAG,CAAC;IAE/D,SAAS,CAAC,IAAe;QACvB,OAAO,IAAI,CAAC,YAAY,EAAE;aACvB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;aAC1C,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAEO,YAAY;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAoB,gDAA8B,CAAC,CAAC;IAC9E,CAAC;CACF,CAAA;AAZY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE4B,+BAAoB;GADhD,aAAa,CAYzB"}
@@ -0,0 +1,22 @@
1
+ import type { Payload } from 'nats';
2
+ import type { EventPayload, EventType } from './event.type';
3
+ export interface EventCodec<E extends EventType> {
4
+ decode<P extends EventPayload<E> = EventPayload<E>>(payload: Payload): P;
5
+ encode<P extends EventPayload<E> = EventPayload<E>>(payload: P): Payload;
6
+ }
7
+ /**
8
+ * Protobuf-encoding strategy
9
+ */
10
+ export declare class ProtoEventCodec<E extends EventType> implements EventCodec<E> {
11
+ readonly eventType: E;
12
+ constructor(eventType: E);
13
+ decode<P extends EventPayload<E>>(buffer: Buffer): P;
14
+ encode<P extends EventPayload<E>>(payload: P): Buffer;
15
+ }
16
+ /**
17
+ * JSON-encoding strategy
18
+ */
19
+ export declare class JSONEventCodec<E extends EventType> implements EventCodec<E> {
20
+ decode<P extends EventPayload<E>>(payload: string): P;
21
+ encode<P extends EventPayload<E>>(payload: P): Payload;
22
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JSONEventCodec = exports.ProtoEventCodec = void 0;
4
+ /**
5
+ * Protobuf-encoding strategy
6
+ */
7
+ class ProtoEventCodec {
8
+ eventType;
9
+ constructor(eventType) {
10
+ this.eventType = eventType;
11
+ }
12
+ decode(buffer) {
13
+ return this.eventType.decode(buffer);
14
+ }
15
+ encode(payload) {
16
+ return Buffer.from(this.eventType.encode(payload).finish());
17
+ }
18
+ }
19
+ exports.ProtoEventCodec = ProtoEventCodec;
20
+ /**
21
+ * JSON-encoding strategy
22
+ */
23
+ class JSONEventCodec {
24
+ decode(payload) {
25
+ return JSON.parse(payload);
26
+ }
27
+ encode(payload) {
28
+ return JSON.stringify(payload);
29
+ }
30
+ }
31
+ exports.JSONEventCodec = JSONEventCodec;
32
+ //# sourceMappingURL=event.codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.codec.js","sourceRoot":"","sources":["../src/event.codec.ts"],"names":[],"mappings":";;;AAUA;;GAEG;AACH,MAAa,eAAe;IACL;IAArB,YAAqB,SAAY;QAAZ,cAAS,GAAT,SAAS,CAAG;IAAG,CAAC;IAErC,MAAM,CAA4B,MAAc;QAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,CAA4B,OAAU;QAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF;AAVD,0CAUC;AAED;;GAEG;AACH,MAAa,cAAc;IACzB,MAAM,CAA4B,OAAe;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,CAA4B,OAAU;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF;AARD,wCAQC"}
@@ -0,0 +1,23 @@
1
+ import type { Reader, Writer } from 'protobufjs/minimal';
2
+ /**
3
+ * Генерируется при компиляции proto-файлов
4
+ */
5
+ export interface EventType<T = any> {
6
+ $group: string;
7
+ $partitionKeyField: string | null;
8
+ $type: string;
9
+ encode(message: T): Writer;
10
+ decode(data: Uint8Array | Reader): T;
11
+ }
12
+ /**
13
+ * Выводит тип payload из EventType
14
+ */
15
+ export type EventPayload<E extends EventType> = E extends EventType<infer P> ? P : never;
16
+ /**
17
+ * Проверяет, является ли переданный тип EventType
18
+ */
19
+ export declare const isEventType: <T = any>(x: any) => x is EventType<T>;
20
+ /**
21
+ * Генерирует имя subject из EventType
22
+ */
23
+ export declare const getSubjectName: (eventType: EventType, partitionKey?: string) => string;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSubjectName = exports.isEventType = void 0;
4
+ /**
5
+ * Проверяет, является ли переданный тип EventType
6
+ */
7
+ const isEventType = (x) => typeof x === 'object' &&
8
+ typeof x.$type === 'string' &&
9
+ typeof x.$group === 'string';
10
+ exports.isEventType = isEventType;
11
+ /**
12
+ * Генерирует имя subject из EventType
13
+ */
14
+ const getSubjectName = (eventType, partitionKey) => {
15
+ return `events.${eventType.$type}${partitionKey ? `.${partitionKey}` : ''}`;
16
+ };
17
+ exports.getSubjectName = getSubjectName;
18
+ //# sourceMappingURL=event.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.type.js","sourceRoot":"","sources":["../src/event.type.ts"],"names":[],"mappings":";;;AAqBA;;GAEG;AACI,MAAM,WAAW,GAAG,CAAU,CAAM,EAAqB,EAAE,CAChE,OAAO,CAAC,KAAK,QAAQ;IACrB,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;IAC3B,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;AAHlB,QAAA,WAAW,eAGO;AAE/B;;GAEG;AACI,MAAM,cAAc,GAAG,CAC5B,SAAoB,EACpB,YAAqB,EACb,EAAE;IACV,OAAO,UAAU,SAAS,CAAC,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC9E,CAAC,CAAC;AALW,QAAA,cAAc,kBAKzB"}
@@ -0,0 +1 @@
1
+ export declare const handleNatsException: (error: unknown, pattern: string, details?: unknown) => never;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleNatsException = void 0;
4
+ const unknown_nats_exception_1 = require("./unknown-nats.exception");
5
+ const handleNatsException = (error, pattern, details) => {
6
+ throw new unknown_nats_exception_1.UnknownNatsException(error, pattern, details);
7
+ };
8
+ exports.handleNatsException = handleNatsException;
9
+ //# sourceMappingURL=exception.handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exception.handler.js","sourceRoot":"","sources":["../../src/exceptions/exception.handler.ts"],"names":[],"mappings":";;;AAAA,qEAAgE;AAEzD,MAAM,mBAAmB,GAAG,CACjC,KAAc,EACd,OAAe,EACf,OAAiB,EACV,EAAE;IACT,MAAM,IAAI,6CAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC,CAAC;AANW,QAAA,mBAAmB,uBAM9B"}
@@ -0,0 +1,6 @@
1
+ import type { ExceptionsProps } from '@rsdk/core';
2
+ import { InternalException } from '@rsdk/core';
3
+ export declare class MissingStreamOrSubjectException extends InternalException {
4
+ readonly topics: string[];
5
+ constructor(topics: string[], props?: ExceptionsProps);
6
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MissingStreamOrSubjectException = void 0;
4
+ const core_1 = require("@rsdk/core");
5
+ class MissingStreamOrSubjectException extends core_1.InternalException {
6
+ topics;
7
+ constructor(topics, props = {}) {
8
+ super('Expected stream or subject not found', {
9
+ ...props,
10
+ details: {
11
+ ...props.details,
12
+ topics,
13
+ },
14
+ });
15
+ this.topics = topics;
16
+ }
17
+ }
18
+ exports.MissingStreamOrSubjectException = MissingStreamOrSubjectException;
19
+ //# sourceMappingURL=missing-topics.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-topics.exception.js","sourceRoot":"","sources":["../../src/exceptions/missing-topics.exception.ts"],"names":[],"mappings":";;;AACA,qCAA+C;AAE/C,MAAa,+BAAgC,SAAQ,wBAAiB;IAEzD;IADX,YACW,MAAgB,EACzB,QAAyB,EAAE;QAE3B,KAAK,CAAC,sCAAsC,EAAE;YAC5C,GAAG,KAAK;YACR,OAAO,EAAE;gBACP,GAAG,KAAK,CAAC,OAAO;gBAChB,MAAM;aACP;SACF,CAAC,CAAC;QATM,WAAM,GAAN,MAAM,CAAU;IAU3B,CAAC;CACF;AAbD,0EAaC"}
@@ -0,0 +1,5 @@
1
+ import type { EnumValue } from '@rsdk/common';
2
+ import { BootstrapException } from '@rsdk/core';
3
+ export declare class PayloadFormatException extends BootstrapException {
4
+ constructor(value: string, allowed: EnumValue[]);
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PayloadFormatException = void 0;
4
+ const core_1 = require("@rsdk/core");
5
+ class PayloadFormatException extends core_1.BootstrapException {
6
+ constructor(value, allowed) {
7
+ super(`PayloadFormat has wrong value: ${value}, allowed: ${allowed.join(',')}`);
8
+ }
9
+ }
10
+ exports.PayloadFormatException = PayloadFormatException;
11
+ //# sourceMappingURL=payload-format.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-format.exception.js","sourceRoot":"","sources":["../../src/exceptions/payload-format.exception.ts"],"names":[],"mappings":";;;AACA,qCAAgD;AAEhD,MAAa,sBAAuB,SAAQ,yBAAkB;IAC5D,YAAY,KAAa,EAAE,OAAoB;QAC7C,KAAK,CACH,kCAAkC,KAAK,cAAc,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACzE,CAAC;IACJ,CAAC;CACF;AAND,wDAMC"}
@@ -0,0 +1,4 @@
1
+ import { InternalException } from '@rsdk/core';
2
+ export declare class UnknownNatsException extends InternalException {
3
+ constructor(cause: unknown, pattern: string, details?: unknown);
4
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnknownNatsException = void 0;
4
+ const core_1 = require("@rsdk/core");
5
+ class UnknownNatsException extends core_1.InternalException {
6
+ constructor(cause, pattern, details) {
7
+ super('Unknown exception from Nats Server', {
8
+ details: {
9
+ pattern,
10
+ details: details,
11
+ },
12
+ cause,
13
+ });
14
+ }
15
+ }
16
+ exports.UnknownNatsException = UnknownNatsException;
17
+ //# sourceMappingURL=unknown-nats.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-nats.exception.js","sourceRoot":"","sources":["../../src/exceptions/unknown-nats.exception.ts"],"names":[],"mappings":";;;AAAA,qCAA+C;AAE/C,MAAa,oBAAqB,SAAQ,wBAAiB;IACzD,YAAY,KAAc,EAAE,OAAe,EAAE,OAAiB;QAC5D,KAAK,CAAC,oCAAoC,EAAE;YAC1C,OAAO,EAAE;gBACP,OAAO;gBACP,OAAO,EAAE,OAAO;aACjB;YACD,KAAK;SACN,CAAC,CAAC;IACL,CAAC;CACF;AAVD,oDAUC"}
@@ -0,0 +1,8 @@
1
+ export { EventType, EventPayload, isEventType, getSubjectName, } from './event.type';
2
+ export { EventCodec, ProtoEventCodec, JSONEventCodec } from './event.codec';
3
+ export { PayloadFormat, DEFAULT_PAYLOAD_FORMAT, X_FORMAT_HEADER, X_TYPE_HEADER, } from './payload.format';
4
+ export { NatsTopicMetadata, NatsTopicMetadataByEventType, NatsTopicMetadataByTopic, TopicType, NATS_TOPIC_RSDK_METADATA_SCOPE, } from './client/client.metadata';
5
+ export { NATS_CLIENT_INJECTION_TOKEN, NATS_PRODUCER_INJECTION_TOKEN, } from './client/client.constants';
6
+ export type { Producer } from './client/producer.provider';
7
+ export { NatsClientModule } from './client/client.module';
8
+ export { handleNatsException } from './exceptions/exception.handler';
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleNatsException = exports.NatsClientModule = exports.NATS_PRODUCER_INJECTION_TOKEN = exports.NATS_CLIENT_INJECTION_TOKEN = exports.NATS_TOPIC_RSDK_METADATA_SCOPE = exports.TopicType = exports.X_TYPE_HEADER = exports.X_FORMAT_HEADER = exports.DEFAULT_PAYLOAD_FORMAT = exports.PayloadFormat = exports.JSONEventCodec = exports.ProtoEventCodec = exports.getSubjectName = exports.isEventType = void 0;
4
+ var event_type_1 = require("./event.type");
5
+ Object.defineProperty(exports, "isEventType", { enumerable: true, get: function () { return event_type_1.isEventType; } });
6
+ Object.defineProperty(exports, "getSubjectName", { enumerable: true, get: function () { return event_type_1.getSubjectName; } });
7
+ var event_codec_1 = require("./event.codec");
8
+ Object.defineProperty(exports, "ProtoEventCodec", { enumerable: true, get: function () { return event_codec_1.ProtoEventCodec; } });
9
+ Object.defineProperty(exports, "JSONEventCodec", { enumerable: true, get: function () { return event_codec_1.JSONEventCodec; } });
10
+ var payload_format_1 = require("./payload.format");
11
+ Object.defineProperty(exports, "PayloadFormat", { enumerable: true, get: function () { return payload_format_1.PayloadFormat; } });
12
+ Object.defineProperty(exports, "DEFAULT_PAYLOAD_FORMAT", { enumerable: true, get: function () { return payload_format_1.DEFAULT_PAYLOAD_FORMAT; } });
13
+ Object.defineProperty(exports, "X_FORMAT_HEADER", { enumerable: true, get: function () { return payload_format_1.X_FORMAT_HEADER; } });
14
+ Object.defineProperty(exports, "X_TYPE_HEADER", { enumerable: true, get: function () { return payload_format_1.X_TYPE_HEADER; } });
15
+ var client_metadata_1 = require("./client/client.metadata");
16
+ Object.defineProperty(exports, "TopicType", { enumerable: true, get: function () { return client_metadata_1.TopicType; } });
17
+ Object.defineProperty(exports, "NATS_TOPIC_RSDK_METADATA_SCOPE", { enumerable: true, get: function () { return client_metadata_1.NATS_TOPIC_RSDK_METADATA_SCOPE; } });
18
+ var client_constants_1 = require("./client/client.constants");
19
+ Object.defineProperty(exports, "NATS_CLIENT_INJECTION_TOKEN", { enumerable: true, get: function () { return client_constants_1.NATS_CLIENT_INJECTION_TOKEN; } });
20
+ Object.defineProperty(exports, "NATS_PRODUCER_INJECTION_TOKEN", { enumerable: true, get: function () { return client_constants_1.NATS_PRODUCER_INJECTION_TOKEN; } });
21
+ var client_module_1 = require("./client/client.module");
22
+ Object.defineProperty(exports, "NatsClientModule", { enumerable: true, get: function () { return client_module_1.NatsClientModule; } });
23
+ var exception_handler_1 = require("./exceptions/exception.handler");
24
+ Object.defineProperty(exports, "handleNatsException", { enumerable: true, get: function () { return exception_handler_1.handleNatsException; } });
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAKsB;AAFpB,yGAAA,WAAW,OAAA;AACX,4GAAA,cAAc,OAAA;AAEhB,6CAA4E;AAAvD,8GAAA,eAAe,OAAA;AAAE,6GAAA,cAAc,OAAA;AACpD,mDAK0B;AAJxB,+GAAA,aAAa,OAAA;AACb,wHAAA,sBAAsB,OAAA;AACtB,iHAAA,eAAe,OAAA;AACf,+GAAA,aAAa,OAAA;AAEf,4DAMkC;AAFhC,4GAAA,SAAS,OAAA;AACT,iIAAA,8BAA8B,OAAA;AAEhC,8DAGmC;AAFjC,+HAAA,2BAA2B,OAAA;AAC3B,iIAAA,6BAA6B,OAAA;AAG/B,wDAA0D;AAAjD,iHAAA,gBAAgB,OAAA;AACzB,oEAAqE;AAA5D,wHAAA,mBAAmB,OAAA"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Способ сериализации данных события
3
+ */
4
+ export declare enum PayloadFormat {
5
+ PROTOBUF = "protobuf",
6
+ JSON = "json"
7
+ }
8
+ /**
9
+ * Проверяет, является ли переданная строка - одним
10
+ * из значений перечисления PayloadFormat
11
+ */
12
+ export declare const isPayloadFormat: (value: string) => value is PayloadFormat;
13
+ /**
14
+ * Проверяет, является ли переданная строка - одним
15
+ * из значений перечисления PayloadFormat. В случае,
16
+ * если передано неверное значение - бросает ошибку
17
+ */
18
+ export declare const assertIsPayloadFormat: (value: string) => asserts value is PayloadFormat;
19
+ /**
20
+ * Заголовок в kafka, через который передаётся способ
21
+ * сериализации
22
+ */
23
+ export declare const X_FORMAT_HEADER = "X-Format";
24
+ /**
25
+ * Сериализация по умолчанию (protobuf)
26
+ */
27
+ export declare const DEFAULT_PAYLOAD_FORMAT = PayloadFormat.PROTOBUF;
28
+ /**
29
+ * Заголовок в nats, через который передаётся тип сообщения
30
+ */
31
+ export declare const X_TYPE_HEADER = "X-Type";
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.X_TYPE_HEADER = exports.DEFAULT_PAYLOAD_FORMAT = exports.X_FORMAT_HEADER = exports.assertIsPayloadFormat = exports.isPayloadFormat = exports.PayloadFormat = void 0;
4
+ const common_1 = require("@rsdk/common");
5
+ const payload_format_exception_1 = require("./exceptions/payload-format.exception");
6
+ /**
7
+ * Способ сериализации данных события
8
+ */
9
+ var PayloadFormat;
10
+ (function (PayloadFormat) {
11
+ PayloadFormat["PROTOBUF"] = "protobuf";
12
+ PayloadFormat["JSON"] = "json";
13
+ })(PayloadFormat || (exports.PayloadFormat = PayloadFormat = {}));
14
+ const allowed = common_1.Enum.values(PayloadFormat);
15
+ /**
16
+ * Проверяет, является ли переданная строка - одним
17
+ * из значений перечисления PayloadFormat
18
+ */
19
+ const isPayloadFormat = (value) => allowed.includes(value);
20
+ exports.isPayloadFormat = isPayloadFormat;
21
+ /**
22
+ * Проверяет, является ли переданная строка - одним
23
+ * из значений перечисления PayloadFormat. В случае,
24
+ * если передано неверное значение - бросает ошибку
25
+ */
26
+ const assertIsPayloadFormat = (value) => {
27
+ if ((0, exports.isPayloadFormat)(value)) {
28
+ return;
29
+ }
30
+ throw new payload_format_exception_1.PayloadFormatException(value, allowed);
31
+ };
32
+ exports.assertIsPayloadFormat = assertIsPayloadFormat;
33
+ /**
34
+ * Заголовок в kafka, через который передаётся способ
35
+ * сериализации
36
+ */
37
+ exports.X_FORMAT_HEADER = 'X-Format';
38
+ /**
39
+ * Сериализация по умолчанию (protobuf)
40
+ */
41
+ exports.DEFAULT_PAYLOAD_FORMAT = PayloadFormat.PROTOBUF;
42
+ /**
43
+ * Заголовок в nats, через который передаётся тип сообщения
44
+ */
45
+ exports.X_TYPE_HEADER = 'X-Type';
46
+ //# sourceMappingURL=payload.format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.format.js","sourceRoot":"","sources":["../src/payload.format.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AAEpC,oFAA+E;AAE/E;;GAEG;AACH,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,sCAAqB,CAAA;IACrB,8BAAa,CAAA;AACf,CAAC,EAHW,aAAa,6BAAb,aAAa,QAGxB;AAED,MAAM,OAAO,GAAG,aAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAE3C;;;GAGG;AACI,MAAM,eAAe,GAAG,CAAC,KAAa,EAA0B,EAAE,CACvE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AADb,QAAA,eAAe,mBACF;AAE1B;;;;GAIG;AACI,MAAM,qBAAqB,GAAG,CACnC,KAAa,EACmB,EAAE;IAClC,IAAI,IAAA,uBAAe,EAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,IAAI,iDAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC,CAAC;AARW,QAAA,qBAAqB,yBAQhC;AAEF;;;GAGG;AACU,QAAA,eAAe,GAAG,UAAU,CAAC;AAE1C;;GAEG;AACU,QAAA,sBAAsB,GAAG,aAAa,CAAC,QAAQ,CAAC;AAE7D;;GAEG;AACU,QAAA,aAAa,GAAG,QAAQ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@rsdk/nats.common",
3
+ "version": "5.3.0-next.4",
4
+ "description": "Common functionality for nats consumers and producers",
5
+ "license": "Apache License 2.0",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "url": "https://github.com/R-Vision/rsdk"
11
+ },
12
+ "main": "dist/index.js",
13
+ "peerDependencies": {
14
+ "@nestjs/common": "^10.0.0",
15
+ "@nestjs/core": "^10.0.0",
16
+ "@nestjs/microservices": "^10.0.0",
17
+ "@rsdk/common": "*",
18
+ "@rsdk/core": "*",
19
+ "@rsdk/logging": "*",
20
+ "@rsdk/metadata": "*",
21
+ "nats": "^2.28.2",
22
+ "reflect-metadata": "^0.1.12 || ^0.2.0",
23
+ "rxjs": "^7.8.1"
24
+ },
25
+ "dependencies": {
26
+ "lodash": "^4.17.21",
27
+ "protobufjs": "^7.2.3"
28
+ },
29
+ "gitHead": "6d80aacd87b9cc36cfcff8c0c050e4fe31810276"
30
+ }
@@ -0,0 +1,24 @@
1
+ import {
2
+ ArrayParser,
3
+ BoolParser,
4
+ Config,
5
+ ConfigSection,
6
+ Property,
7
+ StringParser,
8
+ } from '@rsdk/core';
9
+
10
+ export const NatsConfigInstance = Symbol('NatsConfigInstance');
11
+
12
+ @ConfigSection()
13
+ export class DefaultNatsConfig extends Config {
14
+ @Property('NATS_SERVERS', new ArrayParser(new StringParser()), {
15
+ description: 'NATS server URLs',
16
+ })
17
+ servers!: string[];
18
+
19
+ @Property('NATS_DEBUG', new BoolParser(), {
20
+ defaultValue: false,
21
+ description: 'Enable NATS debug',
22
+ })
23
+ debug!: boolean;
24
+ }
@@ -0,0 +1,2 @@
1
+ export const NATS_CLIENT_INJECTION_TOKEN = Symbol('NatsClient');
2
+ export const NATS_PRODUCER_INJECTION_TOKEN = Symbol('NatsProducer');
@@ -0,0 +1,12 @@
1
+ import { Inject } from '@nestjs/common';
2
+
3
+ import {
4
+ NATS_CLIENT_INJECTION_TOKEN,
5
+ NATS_PRODUCER_INJECTION_TOKEN,
6
+ } from './client.constants';
7
+
8
+ export const InjectNatsClient = (): ParameterDecorator =>
9
+ Inject(NATS_CLIENT_INJECTION_TOKEN);
10
+
11
+ export const InjectNatsProducer = (): ParameterDecorator =>
12
+ Inject(NATS_PRODUCER_INJECTION_TOKEN);
@@ -0,0 +1,30 @@
1
+ import type { EventType } from '../event.type';
2
+
3
+ export enum TopicType {
4
+ // CONSUME,
5
+ PRODUCE,
6
+ }
7
+
8
+ /**
9
+ * TODO: Здесь надо разбираться с неймингом. Потому что хрен
10
+ * поймёшь сейчас, что это за типы
11
+ */
12
+
13
+ export type NatsTopicMetadataByTopic = {
14
+ type: TopicType;
15
+ topicName: string;
16
+ };
17
+
18
+ export type NatsTopicMetadataByEventType = {
19
+ type: TopicType;
20
+ topicName: string;
21
+ group: string;
22
+ partitionKeyField: string | null;
23
+ eventType?: Pick<EventType, '$type' | '$group' | '$partitionKeyField'>;
24
+ };
25
+
26
+ export type NatsTopicMetadata =
27
+ | NatsTopicMetadataByEventType
28
+ | NatsTopicMetadataByTopic;
29
+
30
+ export const NATS_TOPIC_RSDK_METADATA_SCOPE = 'nats-stream';
@@ -0,0 +1,15 @@
1
+ import { Global, Module } from '@nestjs/common';
2
+ import { PlatformConfigModule } from '@rsdk/core';
3
+
4
+ import { DefaultNatsConfig } from './client.config';
5
+ import { natsProvider } from './client.provider';
6
+ import { natsProducerProvider } from './producer.provider';
7
+ import { TopicsService } from './topics.service';
8
+
9
+ @Global()
10
+ @Module({
11
+ imports: [PlatformConfigModule.forFeature(DefaultNatsConfig)],
12
+ providers: [natsProducerProvider, natsProvider, TopicsService],
13
+ exports: [natsProducerProvider, natsProvider, TopicsService],
14
+ })
15
+ export class NatsClientModule {}
@@ -0,0 +1,21 @@
1
+ import type { FactoryProvider } from '@nestjs/common';
2
+ import { APP_NAME } from '@rsdk/core';
3
+ import type { NatsConnection } from 'nats';
4
+ import { connect } from 'nats';
5
+
6
+ import { DefaultNatsConfig } from './client.config';
7
+ import { NATS_CLIENT_INJECTION_TOKEN } from './client.constants';
8
+
9
+ export const natsProvider: FactoryProvider = {
10
+ inject: [DefaultNatsConfig, APP_NAME],
11
+ provide: NATS_CLIENT_INJECTION_TOKEN,
12
+ async useFactory(
13
+ config: DefaultNatsConfig,
14
+ name: string,
15
+ ): Promise<NatsConnection> {
16
+ return await connect({
17
+ name: `${name}-${process.pid}`,
18
+ ...config,
19
+ });
20
+ },
21
+ };
@@ -0,0 +1,17 @@
1
+ import type { FactoryProvider } from '@nestjs/common';
2
+ import type { JetStreamClient, NatsConnection } from 'nats';
3
+
4
+ import {
5
+ NATS_CLIENT_INJECTION_TOKEN,
6
+ NATS_PRODUCER_INJECTION_TOKEN,
7
+ } from './client.constants';
8
+
9
+ export type Producer = JetStreamClient;
10
+
11
+ export const natsProducerProvider: FactoryProvider = {
12
+ inject: [NATS_CLIENT_INJECTION_TOKEN],
13
+ provide: NATS_PRODUCER_INJECTION_TOKEN,
14
+ async useFactory(client: NatsConnection): Promise<Producer> {
15
+ return client.jetstream();
16
+ },
17
+ };
@@ -0,0 +1,21 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import type { Resource } from '@rsdk/metadata';
3
+ import { RsdkMetadataProvider } from '@rsdk/metadata';
4
+
5
+ import type { NatsTopicMetadata, TopicType } from './client.metadata';
6
+ import { NATS_TOPIC_RSDK_METADATA_SCOPE } from './client.metadata';
7
+
8
+ @Injectable()
9
+ export class TopicsService {
10
+ constructor(private readonly provider: RsdkMetadataProvider) {}
11
+
12
+ getTopics(type: TopicType): string[] {
13
+ return this.getResources()
14
+ .filter(({ value }) => value.type === type)
15
+ .map(({ value }) => value.topicName);
16
+ }
17
+
18
+ private getResources(): Resource<NatsTopicMetadata>[] {
19
+ return this.provider.get<NatsTopicMetadata>(NATS_TOPIC_RSDK_METADATA_SCOPE);
20
+ }
21
+ }
@@ -0,0 +1,37 @@
1
+ import type { Payload } from 'nats';
2
+
3
+ import type { EventPayload, EventType } from './event.type';
4
+
5
+ export interface EventCodec<E extends EventType> {
6
+ decode<P extends EventPayload<E> = EventPayload<E>>(payload: Payload): P;
7
+
8
+ encode<P extends EventPayload<E> = EventPayload<E>>(payload: P): Payload;
9
+ }
10
+
11
+ /**
12
+ * Protobuf-encoding strategy
13
+ */
14
+ export class ProtoEventCodec<E extends EventType> implements EventCodec<E> {
15
+ constructor(readonly eventType: E) {}
16
+
17
+ decode<P extends EventPayload<E>>(buffer: Buffer): P {
18
+ return this.eventType.decode(buffer);
19
+ }
20
+
21
+ encode<P extends EventPayload<E>>(payload: P): Buffer {
22
+ return Buffer.from(this.eventType.encode(payload).finish());
23
+ }
24
+ }
25
+
26
+ /**
27
+ * JSON-encoding strategy
28
+ */
29
+ export class JSONEventCodec<E extends EventType> implements EventCodec<E> {
30
+ decode<P extends EventPayload<E>>(payload: string): P {
31
+ return JSON.parse(payload);
32
+ }
33
+
34
+ encode<P extends EventPayload<E>>(payload: P): Payload {
35
+ return JSON.stringify(payload);
36
+ }
37
+ }
@@ -0,0 +1,38 @@
1
+ import type { Reader, Writer } from 'protobufjs/minimal';
2
+
3
+ /**
4
+ * Генерируется при компиляции proto-файлов
5
+ */
6
+ export interface EventType<T = any> {
7
+ $group: string;
8
+ $partitionKeyField: string | null;
9
+ $type: string;
10
+
11
+ encode(message: T): Writer;
12
+
13
+ decode(data: Uint8Array | Reader): T;
14
+ }
15
+
16
+ /**
17
+ * Выводит тип payload из EventType
18
+ */
19
+ export type EventPayload<E extends EventType> =
20
+ E extends EventType<infer P> ? P : never;
21
+
22
+ /**
23
+ * Проверяет, является ли переданный тип EventType
24
+ */
25
+ export const isEventType = <T = any>(x: any): x is EventType<T> =>
26
+ typeof x === 'object' &&
27
+ typeof x.$type === 'string' &&
28
+ typeof x.$group === 'string';
29
+
30
+ /**
31
+ * Генерирует имя subject из EventType
32
+ */
33
+ export const getSubjectName = (
34
+ eventType: EventType,
35
+ partitionKey?: string,
36
+ ): string => {
37
+ return `events.${eventType.$type}${partitionKey ? `.${partitionKey}` : ''}`;
38
+ };
@@ -0,0 +1,9 @@
1
+ import { UnknownNatsException } from './unknown-nats.exception';
2
+
3
+ export const handleNatsException = (
4
+ error: unknown,
5
+ pattern: string,
6
+ details?: unknown,
7
+ ): never => {
8
+ throw new UnknownNatsException(error, pattern, details);
9
+ };
@@ -0,0 +1,17 @@
1
+ import type { ExceptionsProps } from '@rsdk/core';
2
+ import { InternalException } from '@rsdk/core';
3
+
4
+ export class MissingStreamOrSubjectException extends InternalException {
5
+ constructor(
6
+ readonly topics: string[],
7
+ props: ExceptionsProps = {},
8
+ ) {
9
+ super('Expected stream or subject not found', {
10
+ ...props,
11
+ details: {
12
+ ...props.details,
13
+ topics,
14
+ },
15
+ });
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ import type { EnumValue } from '@rsdk/common';
2
+ import { BootstrapException } from '@rsdk/core';
3
+
4
+ export class PayloadFormatException extends BootstrapException {
5
+ constructor(value: string, allowed: EnumValue[]) {
6
+ super(
7
+ `PayloadFormat has wrong value: ${value}, allowed: ${allowed.join(',')}`,
8
+ );
9
+ }
10
+ }
@@ -0,0 +1,13 @@
1
+ import { InternalException } from '@rsdk/core';
2
+
3
+ export class UnknownNatsException extends InternalException {
4
+ constructor(cause: unknown, pattern: string, details?: unknown) {
5
+ super('Unknown exception from Nats Server', {
6
+ details: {
7
+ pattern,
8
+ details: details,
9
+ },
10
+ cause,
11
+ });
12
+ }
13
+ }
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ export {
2
+ EventType,
3
+ EventPayload,
4
+ isEventType,
5
+ getSubjectName,
6
+ } from './event.type';
7
+ export { EventCodec, ProtoEventCodec, JSONEventCodec } from './event.codec';
8
+ export {
9
+ PayloadFormat,
10
+ DEFAULT_PAYLOAD_FORMAT,
11
+ X_FORMAT_HEADER,
12
+ X_TYPE_HEADER,
13
+ } from './payload.format';
14
+ export {
15
+ NatsTopicMetadata,
16
+ NatsTopicMetadataByEventType,
17
+ NatsTopicMetadataByTopic,
18
+ TopicType,
19
+ NATS_TOPIC_RSDK_METADATA_SCOPE,
20
+ } from './client/client.metadata';
21
+ export {
22
+ NATS_CLIENT_INJECTION_TOKEN,
23
+ NATS_PRODUCER_INJECTION_TOKEN,
24
+ } from './client/client.constants';
25
+ export type { Producer } from './client/producer.provider';
26
+ export { NatsClientModule } from './client/client.module';
27
+ export { handleNatsException } from './exceptions/exception.handler';
@@ -0,0 +1,51 @@
1
+ import { Enum } from '@rsdk/common';
2
+
3
+ import { PayloadFormatException } from './exceptions/payload-format.exception';
4
+
5
+ /**
6
+ * Способ сериализации данных события
7
+ */
8
+ export enum PayloadFormat {
9
+ PROTOBUF = 'protobuf',
10
+ JSON = 'json',
11
+ }
12
+
13
+ const allowed = Enum.values(PayloadFormat);
14
+
15
+ /**
16
+ * Проверяет, является ли переданная строка - одним
17
+ * из значений перечисления PayloadFormat
18
+ */
19
+ export const isPayloadFormat = (value: string): value is PayloadFormat =>
20
+ allowed.includes(value);
21
+
22
+ /**
23
+ * Проверяет, является ли переданная строка - одним
24
+ * из значений перечисления PayloadFormat. В случае,
25
+ * если передано неверное значение - бросает ошибку
26
+ */
27
+ export const assertIsPayloadFormat = (
28
+ value: string,
29
+ ): asserts value is PayloadFormat => {
30
+ if (isPayloadFormat(value)) {
31
+ return;
32
+ }
33
+
34
+ throw new PayloadFormatException(value, allowed);
35
+ };
36
+
37
+ /**
38
+ * Заголовок в kafka, через который передаётся способ
39
+ * сериализации
40
+ */
41
+ export const X_FORMAT_HEADER = 'X-Format';
42
+
43
+ /**
44
+ * Сериализация по умолчанию (protobuf)
45
+ */
46
+ export const DEFAULT_PAYLOAD_FORMAT = PayloadFormat.PROTOBUF;
47
+
48
+ /**
49
+ * Заголовок в nats, через который передаётся тип сообщения
50
+ */
51
+ export const X_TYPE_HEADER = 'X-Type';
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [
4
+ "node_modules",
5
+ "dist",
6
+ "test",
7
+ "**/*.spec.ts",
8
+ "**/*.test.ts",
9
+ "**/*.test.e2e.ts",
10
+ "**/*.test.manual-e2e.ts",
11
+ ]
12
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@rsdk/tsconfig/base.json",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "outDir": "dist"
6
+ }
7
+ }