@riaskov/nevo-messaging 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +831 -0
- package/dist/common/base.client.d.ts +12 -0
- package/dist/common/base.client.js +50 -0
- package/dist/common/base.controller.d.ts +28 -0
- package/dist/common/base.controller.js +159 -0
- package/dist/common/bigint.utils.d.ts +7 -0
- package/dist/common/bigint.utils.js +50 -0
- package/dist/common/error-code.d.ts +3 -0
- package/dist/common/error-code.js +7 -0
- package/dist/common/error-messages.d.ts +1 -0
- package/dist/common/error-messages.js +7 -0
- package/dist/common/errors.d.ts +9 -0
- package/dist/common/errors.js +41 -0
- package/dist/common/index.d.ts +8 -0
- package/dist/common/index.js +24 -0
- package/dist/common/service-utils.d.ts +21 -0
- package/dist/common/service-utils.js +54 -0
- package/dist/common/signal-router.decorator.d.ts +9 -0
- package/dist/common/signal-router.decorator.js +67 -0
- package/dist/common/types.d.ts +72 -0
- package/dist/common/types.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -0
- package/dist/signal-router.utils.d.ts +28 -0
- package/dist/signal-router.utils.js +131 -0
- package/dist/signal.decorator.d.ts +15 -0
- package/dist/signal.decorator.js +67 -0
- package/dist/transports/index.d.ts +1 -0
- package/dist/transports/index.js +17 -0
- package/dist/transports/kafka/index.d.ts +5 -0
- package/dist/transports/kafka/index.js +21 -0
- package/dist/transports/kafka/kafka.client-base.d.ts +8 -0
- package/dist/transports/kafka/kafka.client-base.js +18 -0
- package/dist/transports/kafka/kafka.config.d.ts +16 -0
- package/dist/transports/kafka/kafka.config.js +210 -0
- package/dist/transports/kafka/kafka.signal-router.decorator.d.ts +3 -0
- package/dist/transports/kafka/kafka.signal-router.decorator.js +78 -0
- package/dist/transports/kafka/microservice.config.d.ts +10 -0
- package/dist/transports/kafka/microservice.config.js +46 -0
- package/dist/transports/kafka/nevo-kafka.client.d.ts +16 -0
- package/dist/transports/kafka/nevo-kafka.client.js +87 -0
- package/package.json +64 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MessagePayload, MicroserviceConfig, TransportClientOptions } from "./types";
|
|
2
|
+
export declare abstract class BaseMessagingClient {
|
|
3
|
+
protected readonly options: TransportClientOptions;
|
|
4
|
+
protected readonly microservices: Map<string, string>;
|
|
5
|
+
protected constructor(options?: TransportClientOptions);
|
|
6
|
+
protected registerMicroservices(configs: MicroserviceConfig[]): void;
|
|
7
|
+
protected query<T = any>(serviceName: string, method: string, params: any): Promise<T>;
|
|
8
|
+
protected emit(serviceName: string, method: string, params: any): Promise<void>;
|
|
9
|
+
protected createMessagePayload(method: string, params: any): MessagePayload;
|
|
10
|
+
protected abstract _queryMicroservice<T>(clientName: string, method: string, params: any): Promise<T>;
|
|
11
|
+
protected abstract _emitToMicroservice(clientName: string, method: string, params: any): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseMessagingClient = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const common_1 = require("../common");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
class BaseMessagingClient {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.microservices = new Map();
|
|
10
|
+
this.options = {
|
|
11
|
+
timeout: 20000,
|
|
12
|
+
debug: false,
|
|
13
|
+
...options
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
registerMicroservices(configs) {
|
|
17
|
+
for (const config of configs) {
|
|
18
|
+
this.microservices.set(config.serviceName, config.clientName);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async query(serviceName, method, params) {
|
|
22
|
+
const clientName = this.microservices.get(serviceName);
|
|
23
|
+
if (!clientName) {
|
|
24
|
+
throw new errors_1.MessagingError(common_1.ErrorCode.UNKNOWN, {
|
|
25
|
+
message: `Microservice ${serviceName} is not registered`,
|
|
26
|
+
serviceName
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return this._queryMicroservice(clientName, method, params);
|
|
30
|
+
}
|
|
31
|
+
async emit(serviceName, method, params) {
|
|
32
|
+
const clientName = this.microservices.get(serviceName);
|
|
33
|
+
if (!clientName) {
|
|
34
|
+
throw new errors_1.MessagingError(common_1.ErrorCode.UNKNOWN, {
|
|
35
|
+
message: `Microservice ${serviceName} is not registered`,
|
|
36
|
+
serviceName
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return this._emitToMicroservice(clientName, method, params);
|
|
40
|
+
}
|
|
41
|
+
createMessagePayload(method, params) {
|
|
42
|
+
const uuid = (0, node_crypto_1.randomUUID)();
|
|
43
|
+
const request = { uuid, method, params };
|
|
44
|
+
return {
|
|
45
|
+
key: uuid,
|
|
46
|
+
value: JSON.stringify(request)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.BaseMessagingClient = BaseMessagingClient;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AfterHook, BeforeHook, ServiceMethodHandler, ServiceMethodMapping, SystemAfterHook, SystemBeforeHook, MessageResponse } from "./types";
|
|
2
|
+
export declare abstract class BaseMessageController {
|
|
3
|
+
protected readonly methodRegistry: ServiceMethodMapping;
|
|
4
|
+
serviceInstances: any[];
|
|
5
|
+
protected readonly serviceName: string;
|
|
6
|
+
protected readonly beforeHook?: BeforeHook;
|
|
7
|
+
protected readonly afterHook?: AfterHook;
|
|
8
|
+
protected readonly systemBeforeHook: SystemBeforeHook;
|
|
9
|
+
protected readonly systemAfterHook: SystemAfterHook;
|
|
10
|
+
protected readonly debug: boolean;
|
|
11
|
+
protected constructor(serviceName: string, serviceInstances: any[], methodHandlers: ServiceMethodMapping, options?: {
|
|
12
|
+
onBefore?: BeforeHook;
|
|
13
|
+
onAfter?: AfterHook;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
});
|
|
16
|
+
protected registerMethodHandlers(handlers: ServiceMethodMapping): void;
|
|
17
|
+
protected findServiceInstance(methodName: string): any;
|
|
18
|
+
protected executeHandler(handler: ServiceMethodHandler, params: unknown): Promise<unknown>;
|
|
19
|
+
protected formatResult(result: unknown): Promise<unknown>;
|
|
20
|
+
protected createErrorResponse(uuid: string, method: string, error: any): MessageResponse;
|
|
21
|
+
processMessage(data: any): Promise<MessageResponse>;
|
|
22
|
+
protected abstract extractMessageData(data: any): {
|
|
23
|
+
method: string;
|
|
24
|
+
uuid: string;
|
|
25
|
+
params: any;
|
|
26
|
+
};
|
|
27
|
+
abstract handleMessage(data: any): Promise<MessageResponse>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseMessageController = void 0;
|
|
4
|
+
const _1 = require("./");
|
|
5
|
+
class BaseMessageController {
|
|
6
|
+
constructor(serviceName, serviceInstances, methodHandlers, options) {
|
|
7
|
+
this.methodRegistry = {};
|
|
8
|
+
this.serviceInstances = [];
|
|
9
|
+
this.serviceName = serviceName;
|
|
10
|
+
this.serviceInstances = serviceInstances || [];
|
|
11
|
+
this.beforeHook = options?.onBefore;
|
|
12
|
+
this.afterHook = options?.onAfter;
|
|
13
|
+
this.debug = options?.debug || false;
|
|
14
|
+
this.systemBeforeHook = (context) => {
|
|
15
|
+
if (this.debug) {
|
|
16
|
+
console.log(`[${this.constructor.name}] Received:`, {
|
|
17
|
+
method: context.method,
|
|
18
|
+
uuid: context.uuid
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
this.systemAfterHook = (context) => {
|
|
23
|
+
if (this.debug) {
|
|
24
|
+
console.log(`[${this.constructor.name}] Responding:`, {
|
|
25
|
+
method: context.method,
|
|
26
|
+
uuid: context.uuid,
|
|
27
|
+
success: context.response.params.result !== "error"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
if (methodHandlers) {
|
|
32
|
+
this.registerMethodHandlers(methodHandlers);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
registerMethodHandlers(handlers) {
|
|
36
|
+
Object.entries(handlers).forEach(([methodName, handler]) => {
|
|
37
|
+
this.methodRegistry[methodName] = handler;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
findServiceInstance(methodName) {
|
|
41
|
+
for (const instance of this.serviceInstances) {
|
|
42
|
+
if (typeof instance[methodName] === "function") {
|
|
43
|
+
return instance;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
async executeHandler(handler, params) {
|
|
49
|
+
const { serviceMethod, paramTransformer, resultTransformer } = handler;
|
|
50
|
+
const serviceInstance = this.findServiceInstance(serviceMethod);
|
|
51
|
+
if (!serviceInstance) {
|
|
52
|
+
throw new _1.MessagingError(_1.ErrorCode.UNKNOWN, {
|
|
53
|
+
message: `No service found with method: ${serviceMethod}`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const methodArgs = paramTransformer ? paramTransformer(params) : [params];
|
|
57
|
+
try {
|
|
58
|
+
const result = await serviceInstance[serviceMethod](...methodArgs);
|
|
59
|
+
return resultTransformer ? resultTransformer(result) : result;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error.message?.includes("is not a function")) {
|
|
63
|
+
throw new _1.MessagingError(_1.ErrorCode.UNKNOWN, {
|
|
64
|
+
message: `Method '${serviceMethod}' not found in service`
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async formatResult(result) {
|
|
71
|
+
if (result instanceof Promise) {
|
|
72
|
+
result = await result;
|
|
73
|
+
}
|
|
74
|
+
return (0, _1.serializeBigInt)(result);
|
|
75
|
+
}
|
|
76
|
+
createErrorResponse(uuid, method, error) {
|
|
77
|
+
if (error instanceof _1.MessagingError) {
|
|
78
|
+
return {
|
|
79
|
+
uuid,
|
|
80
|
+
method,
|
|
81
|
+
params: {
|
|
82
|
+
result: "error",
|
|
83
|
+
error: error.toJSON()
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
console.error(`Unexpected error in ${method}:`, error);
|
|
88
|
+
return {
|
|
89
|
+
uuid,
|
|
90
|
+
method,
|
|
91
|
+
params: {
|
|
92
|
+
result: "error",
|
|
93
|
+
error: {
|
|
94
|
+
code: _1.ErrorCode.UNKNOWN,
|
|
95
|
+
message: process.env["NODE_ENV"] !== "production" ? error.message : "Internal server error",
|
|
96
|
+
details: {},
|
|
97
|
+
service: this.serviceName
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async processMessage(data) {
|
|
103
|
+
const { method, uuid, params } = this.extractMessageData(data);
|
|
104
|
+
const baseContext = {
|
|
105
|
+
method,
|
|
106
|
+
serviceName: this.serviceName,
|
|
107
|
+
uuid,
|
|
108
|
+
rawData: data
|
|
109
|
+
};
|
|
110
|
+
const requestContext = {
|
|
111
|
+
...baseContext,
|
|
112
|
+
params
|
|
113
|
+
};
|
|
114
|
+
try {
|
|
115
|
+
await this.systemBeforeHook(requestContext);
|
|
116
|
+
let processedParams = params;
|
|
117
|
+
if (this.beforeHook) {
|
|
118
|
+
const hookResult = await this.beforeHook(requestContext);
|
|
119
|
+
if (hookResult !== undefined) {
|
|
120
|
+
processedParams = hookResult;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const handler = this.methodRegistry[method];
|
|
124
|
+
if (!handler) {
|
|
125
|
+
throw new _1.MessagingError(_1.ErrorCode.UNKNOWN, {
|
|
126
|
+
message: `Method handler not found: ${method}`
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const result = await this.executeHandler(handler, processedParams);
|
|
130
|
+
const formattedResult = await this.formatResult(result);
|
|
131
|
+
let response = {
|
|
132
|
+
uuid,
|
|
133
|
+
method,
|
|
134
|
+
params: { result: formattedResult }
|
|
135
|
+
};
|
|
136
|
+
const responseContext = {
|
|
137
|
+
...baseContext,
|
|
138
|
+
params: processedParams,
|
|
139
|
+
result: formattedResult,
|
|
140
|
+
response
|
|
141
|
+
};
|
|
142
|
+
if (this.afterHook) {
|
|
143
|
+
const hookResponse = await this.afterHook(responseContext);
|
|
144
|
+
if (hookResponse !== undefined) {
|
|
145
|
+
response = hookResponse;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await this.systemAfterHook({
|
|
149
|
+
...responseContext,
|
|
150
|
+
response
|
|
151
|
+
});
|
|
152
|
+
return response;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return this.createErrorResponse(uuid, method, error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.BaseMessageController = BaseMessageController;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface BigIntSerializable {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
export declare function serializeBigInt(obj: any): any;
|
|
5
|
+
export declare function deserializeBigInt(obj: any): any;
|
|
6
|
+
export declare function stringifyWithBigInt(obj: any): string;
|
|
7
|
+
export declare function parseWithBigInt(str: string): any;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeBigInt = serializeBigInt;
|
|
4
|
+
exports.deserializeBigInt = deserializeBigInt;
|
|
5
|
+
exports.stringifyWithBigInt = stringifyWithBigInt;
|
|
6
|
+
exports.parseWithBigInt = parseWithBigInt;
|
|
7
|
+
function serializeBigInt(obj) {
|
|
8
|
+
if (obj === null || obj === undefined) {
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
|
11
|
+
if (typeof obj === "bigint") {
|
|
12
|
+
return `${obj.toString()}n`;
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(obj)) {
|
|
15
|
+
return obj.map(serializeBigInt);
|
|
16
|
+
}
|
|
17
|
+
if (typeof obj === "object") {
|
|
18
|
+
const serialized = {};
|
|
19
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
20
|
+
serialized[key] = serializeBigInt(value);
|
|
21
|
+
}
|
|
22
|
+
return serialized;
|
|
23
|
+
}
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
function deserializeBigInt(obj) {
|
|
27
|
+
if (obj === null || obj === undefined) {
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
if (typeof obj === "string" && /^\d+n$/.test(obj)) {
|
|
31
|
+
return BigInt(obj.slice(0, -1));
|
|
32
|
+
}
|
|
33
|
+
if (Array.isArray(obj)) {
|
|
34
|
+
return obj.map(deserializeBigInt);
|
|
35
|
+
}
|
|
36
|
+
if (typeof obj === "object") {
|
|
37
|
+
const deserialized = {};
|
|
38
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
39
|
+
deserialized[key] = deserializeBigInt(value);
|
|
40
|
+
}
|
|
41
|
+
return deserialized;
|
|
42
|
+
}
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
function stringifyWithBigInt(obj) {
|
|
46
|
+
return JSON.stringify(serializeBigInt(obj));
|
|
47
|
+
}
|
|
48
|
+
function parseWithBigInt(str) {
|
|
49
|
+
return deserializeBigInt(JSON.parse(str));
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ErrorMessages: Record<number, string>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ErrorCode, ErrorDetails } from "./";
|
|
2
|
+
export declare class MessagingError extends Error {
|
|
3
|
+
readonly code: ErrorCode;
|
|
4
|
+
readonly details: Record<string, unknown>;
|
|
5
|
+
readonly serviceName: string;
|
|
6
|
+
constructor(code: ErrorCode, options?: Record<string, unknown>, serviceName?: string);
|
|
7
|
+
toJSON(): ErrorDetails;
|
|
8
|
+
static fromJSON(error: ErrorDetails): MessagingError;
|
|
9
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MessagingError = void 0;
|
|
4
|
+
const _1 = require("./");
|
|
5
|
+
class MessagingError extends Error {
|
|
6
|
+
constructor(code, options, serviceName = "unknown") {
|
|
7
|
+
super(options?.["message"] || _1.ErrorMessages[code]);
|
|
8
|
+
this.name = "MessagingError";
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.details = { ...(options || {}) };
|
|
11
|
+
this.serviceName = serviceName;
|
|
12
|
+
if (process.env["MODE"] === "production") {
|
|
13
|
+
this.stack = "";
|
|
14
|
+
}
|
|
15
|
+
else if (this.stack) {
|
|
16
|
+
const stack = this.stack.split("\n");
|
|
17
|
+
this.stack = stack.slice(1).join("\n");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
toJSON() {
|
|
21
|
+
const error = {
|
|
22
|
+
code: this.code,
|
|
23
|
+
message: this.message,
|
|
24
|
+
details: this.details,
|
|
25
|
+
service: this.serviceName
|
|
26
|
+
};
|
|
27
|
+
if (process.env["MODE"] !== "production" && this.stack) {
|
|
28
|
+
error.stack = this.stack;
|
|
29
|
+
}
|
|
30
|
+
return error;
|
|
31
|
+
}
|
|
32
|
+
static fromJSON(error) {
|
|
33
|
+
const { code, message, details, service, stack } = error;
|
|
34
|
+
const messagingError = new MessagingError(code, { message, ...details }, service);
|
|
35
|
+
if (process.env["MODE"] !== "production" && stack) {
|
|
36
|
+
messagingError.stack = stack;
|
|
37
|
+
}
|
|
38
|
+
return messagingError;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.MessagingError = MessagingError;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./errors"), exports);
|
|
19
|
+
__exportStar(require("./base.client"), exports);
|
|
20
|
+
__exportStar(require("./base.controller"), exports);
|
|
21
|
+
__exportStar(require("./service-utils"), exports);
|
|
22
|
+
__exportStar(require("./error-code"), exports);
|
|
23
|
+
__exportStar(require("./error-messages"), exports);
|
|
24
|
+
__exportStar(require("./bigint.utils"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ServiceMethodHandler, ServiceMethodMapping } from "./types";
|
|
2
|
+
export type MethodOf<T> = {
|
|
3
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
|
|
4
|
+
}[keyof T] & string;
|
|
5
|
+
export type ServiceMethod<TParams = unknown, TResult = unknown> = {
|
|
6
|
+
params: TParams;
|
|
7
|
+
result: TResult;
|
|
8
|
+
};
|
|
9
|
+
export type ServiceMethodMap = Record<string, ServiceMethod>;
|
|
10
|
+
export declare function mapServiceMethods<T>(service: T, customMappings?: Record<string, string | [
|
|
11
|
+
string,
|
|
12
|
+
{
|
|
13
|
+
paramTransformer?: (params: unknown) => unknown[];
|
|
14
|
+
resultTransformer?: (result: unknown) => unknown;
|
|
15
|
+
}?
|
|
16
|
+
]>): Record<string, ServiceMethodHandler>;
|
|
17
|
+
export declare const createServiceClient: <T extends ServiceMethodMap>(serviceName: string) => {
|
|
18
|
+
query: <M extends keyof T & string>(method: M, params: T[M]["params"]) => Promise<T[M]["result"]>;
|
|
19
|
+
emit: <M extends keyof T & string>(method: M, params: T[M]["params"]) => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
export declare function createMethodHandlers(mappings: Record<string, [string, ((params: unknown) => unknown[])?, ((result: unknown) => unknown)?]>): ServiceMethodMapping;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createServiceClient = void 0;
|
|
4
|
+
exports.mapServiceMethods = mapServiceMethods;
|
|
5
|
+
exports.createMethodHandlers = createMethodHandlers;
|
|
6
|
+
function mapServiceMethods(service, customMappings) {
|
|
7
|
+
const serviceMethods = Object.getOwnPropertyNames(Object.getPrototypeOf(service)).filter((name) => name !== "constructor" && typeof service[name] === "function");
|
|
8
|
+
const resultMappings = {};
|
|
9
|
+
if (customMappings) {
|
|
10
|
+
Object.entries(customMappings).forEach(([eventName, mapping]) => {
|
|
11
|
+
let methodPrefix;
|
|
12
|
+
let options;
|
|
13
|
+
if (typeof mapping === "string") {
|
|
14
|
+
methodPrefix = mapping;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
;
|
|
18
|
+
[methodPrefix, options] = mapping;
|
|
19
|
+
}
|
|
20
|
+
const matchingMethod = serviceMethods.find((method) => method.toLowerCase().startsWith(methodPrefix.toLowerCase()));
|
|
21
|
+
if (matchingMethod) {
|
|
22
|
+
resultMappings[eventName] = {
|
|
23
|
+
serviceMethod: matchingMethod,
|
|
24
|
+
paramTransformer: options?.paramTransformer,
|
|
25
|
+
resultTransformer: options?.resultTransformer
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return resultMappings;
|
|
31
|
+
}
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
const createServiceClient = (serviceName) => ({
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
query: (method, params) => {
|
|
36
|
+
throw new Error("Implementation required in subclass");
|
|
37
|
+
},
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
emit: (method, params) => {
|
|
40
|
+
throw new Error("Implementation required in subclass");
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
exports.createServiceClient = createServiceClient;
|
|
44
|
+
function createMethodHandlers(mappings) {
|
|
45
|
+
return Object.entries(mappings).reduce((handlers, [methodName, config]) => {
|
|
46
|
+
const [serviceMethod, paramTransformer, resultTransformer] = config;
|
|
47
|
+
handlers[methodName] = {
|
|
48
|
+
serviceMethod,
|
|
49
|
+
paramTransformer,
|
|
50
|
+
resultTransformer
|
|
51
|
+
};
|
|
52
|
+
return handlers;
|
|
53
|
+
}, {});
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { Type } from "@nestjs/common";
|
|
3
|
+
import { BeforeHook, AfterHook } from "./types";
|
|
4
|
+
export declare function createSignalRouterDecorator<T>(controllerClass: Type<T>, serviceType: Type<any> | Type<any>[], options?: {
|
|
5
|
+
before?: BeforeHook;
|
|
6
|
+
after?: AfterHook;
|
|
7
|
+
debug?: boolean;
|
|
8
|
+
eventPattern?: string;
|
|
9
|
+
}): (target: any) => any;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSignalRouterDecorator = createSignalRouterDecorator;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const signal_decorator_1 = require("../signal.decorator");
|
|
7
|
+
function createSignalRouterDecorator(controllerClass, serviceType, options) {
|
|
8
|
+
return function (target) {
|
|
9
|
+
(0, common_1.Controller)()(target);
|
|
10
|
+
const originalPrototype = target.prototype;
|
|
11
|
+
Reflect.defineProperty(target, "prototype", {
|
|
12
|
+
value: {
|
|
13
|
+
...originalPrototype,
|
|
14
|
+
onModuleInit() {
|
|
15
|
+
if (originalPrototype.onModuleInit) {
|
|
16
|
+
originalPrototype.onModuleInit.call(this);
|
|
17
|
+
}
|
|
18
|
+
const serviceInstances = Array.isArray(serviceType)
|
|
19
|
+
? // @ts-ignore
|
|
20
|
+
serviceType.map((type) => this[findPropertyNameByType(this, type)]).filter(Boolean)
|
|
21
|
+
: // @ts-ignore
|
|
22
|
+
[this[findPropertyNameByType(this, serviceType)]].filter(Boolean);
|
|
23
|
+
const signals = (0, signal_decorator_1.getClassSignals)(target);
|
|
24
|
+
const serviceName = options?.eventPattern || target.name.toLowerCase().replace("controller", "");
|
|
25
|
+
const controller = new controllerClass(serviceName, serviceInstances, createHandlersFromSignals(signals), {
|
|
26
|
+
onBefore: options?.before,
|
|
27
|
+
onAfter: options?.after,
|
|
28
|
+
debug: options?.debug
|
|
29
|
+
});
|
|
30
|
+
Object.getOwnPropertyNames(controller).forEach((key) => {
|
|
31
|
+
if (key !== "constructor" && key !== "serviceInstances") {
|
|
32
|
+
this[key] = controller[key];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const controllerProto = Object.getPrototypeOf(controller);
|
|
36
|
+
Object.getOwnPropertyNames(controllerProto).forEach((key) => {
|
|
37
|
+
if (key !== "constructor" && typeof controllerProto[key] === "function") {
|
|
38
|
+
this[key] = controllerProto[key].bind(this);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
writable: true,
|
|
44
|
+
configurable: true
|
|
45
|
+
});
|
|
46
|
+
return target;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function findPropertyNameByType(instance, type) {
|
|
50
|
+
for (const key of Object.keys(instance)) {
|
|
51
|
+
if (instance[key] instanceof type) {
|
|
52
|
+
return key;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function createHandlersFromSignals(signals) {
|
|
58
|
+
return signals.reduce((handlers, signal) => {
|
|
59
|
+
handlers[signal.signalName] = {
|
|
60
|
+
serviceMethod: signal.methodName,
|
|
61
|
+
paramTransformer: signal.paramTransformer,
|
|
62
|
+
resultTransformer: signal.resultTransformer,
|
|
63
|
+
options: signal.options
|
|
64
|
+
};
|
|
65
|
+
return handlers;
|
|
66
|
+
}, {});
|
|
67
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ClientProxy } from "@nestjs/microservices";
|
|
2
|
+
export interface MessagingClientProxy extends ClientProxy {
|
|
3
|
+
subscribeToResponseOf(pattern: string): void;
|
|
4
|
+
}
|
|
5
|
+
export interface MessagePayload {
|
|
6
|
+
key: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MessageRequest<T = unknown> {
|
|
10
|
+
uuid: string;
|
|
11
|
+
method: string;
|
|
12
|
+
params: T;
|
|
13
|
+
}
|
|
14
|
+
export interface MessageResponse<T = unknown> {
|
|
15
|
+
uuid: string;
|
|
16
|
+
method: string;
|
|
17
|
+
params: {
|
|
18
|
+
result: T | "error";
|
|
19
|
+
error?: ErrorDetails;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface ErrorDetails {
|
|
23
|
+
code: number;
|
|
24
|
+
message: string;
|
|
25
|
+
details?: Record<string, unknown>;
|
|
26
|
+
service?: string;
|
|
27
|
+
stack?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface HookContext {
|
|
30
|
+
method: string;
|
|
31
|
+
serviceName: string;
|
|
32
|
+
uuid: string;
|
|
33
|
+
rawData: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface BeforeHookContext extends HookContext {
|
|
36
|
+
params: unknown;
|
|
37
|
+
options?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
export interface AfterHookContext extends HookContext {
|
|
40
|
+
params: unknown;
|
|
41
|
+
result: unknown;
|
|
42
|
+
response: MessageResponse;
|
|
43
|
+
options?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
export type BeforeHook = (context: BeforeHookContext) => Promise<unknown> | unknown;
|
|
46
|
+
export type AfterHook = (context: AfterHookContext) => Promise<MessageResponse> | MessageResponse;
|
|
47
|
+
export type SystemBeforeHook = (context: BeforeHookContext) => Promise<void> | void;
|
|
48
|
+
export type SystemAfterHook = (context: AfterHookContext) => Promise<void> | void;
|
|
49
|
+
export interface ServiceMethodHandler {
|
|
50
|
+
serviceMethod: string;
|
|
51
|
+
paramTransformer?: (params: unknown) => unknown[];
|
|
52
|
+
resultTransformer?: (result: unknown) => unknown;
|
|
53
|
+
options?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
export interface ServiceMethodMapping {
|
|
56
|
+
[methodName: string]: ServiceMethodHandler;
|
|
57
|
+
}
|
|
58
|
+
export interface TransportClientOptions {
|
|
59
|
+
clientId?: string;
|
|
60
|
+
timeout?: number;
|
|
61
|
+
debug?: boolean;
|
|
62
|
+
[key: string]: any;
|
|
63
|
+
}
|
|
64
|
+
export interface TransportServerOptions {
|
|
65
|
+
serviceName: string;
|
|
66
|
+
debug?: boolean;
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
}
|
|
69
|
+
export interface MicroserviceConfig {
|
|
70
|
+
serviceName: string;
|
|
71
|
+
clientName: string;
|
|
72
|
+
}
|
package/dist/index.d.ts
ADDED