@skillstew/common 1.0.26 → 1.0.27
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/build/index.d.ts +0 -11
- package/build/index.js +0 -14
- package/package.json +1 -1
- package/src/index.ts +0 -17
- package/build/errors/AppError.d.ts +0 -14
- package/build/errors/AppError.js +0 -23
- package/build/errors/ForbiddenError.d.ts +0 -5
- package/build/errors/ForbiddenError.js +0 -13
- package/build/errors/JwtErrors.d.ts +0 -24
- package/build/errors/JwtErrors.js +0 -50
- package/build/errors/MessageQueueErrors.d.ts +0 -18
- package/build/errors/MessageQueueErrors.js +0 -45
- package/build/errors/UnauthenticatedError.d.ts +0 -5
- package/build/errors/UnauthenticatedError.js +0 -13
- package/build/errors/UnauthorizedError.d.ts +0 -5
- package/build/errors/UnauthorizedError.js +0 -13
- package/build/errors/codes/JwtErrorCodes.d.ts +0 -8
- package/build/errors/codes/JwtErrorCodes.js +0 -12
- package/build/errors/codes/MessageQueueErrorCodes.d.ts +0 -6
- package/build/errors/codes/MessageQueueErrorCodes.js +0 -9
- package/build/events/Consumer.d.ts +0 -19
- package/build/events/Consumer.js +0 -78
- package/build/events/Producer.d.ts +0 -10
- package/build/events/Producer.js +0 -37
- package/build/jwt-utils/JwtHelper.d.ts +0 -23
- package/build/jwt-utils/JwtHelper.js +0 -43
- package/build/middlewares/authMiddleware.d.ts +0 -6
- package/build/middlewares/authMiddleware.js +0 -52
- package/build/middlewares/requireRole.d.ts +0 -3
- package/build/middlewares/requireRole.js +0 -20
- package/src/errors/AppError.ts +0 -20
- package/src/errors/ForbiddenError.ts +0 -10
- package/src/errors/JwtErrors.ts +0 -47
- package/src/errors/MessageQueueErrors.ts +0 -53
- package/src/errors/UnauthenticatedError.ts +0 -10
- package/src/errors/UnauthorizedError.ts +0 -10
- package/src/errors/codes/JwtErrorCodes.ts +0 -8
- package/src/errors/codes/MessageQueueErrorCodes.ts +0 -6
- package/src/events/Consumer.ts +0 -106
- package/src/events/Producer.ts +0 -30
- package/src/jwt-utils/JwtHelper.ts +0 -74
- package/src/middlewares/authMiddleware.ts +0 -58
- package/src/middlewares/requireRole.ts +0 -17
package/build/index.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
export * from "./errors/AppError";
|
|
2
|
-
export * from "./errors/JwtErrors";
|
|
3
|
-
export * from "./errors/UnauthenticatedError";
|
|
4
|
-
export * from "./errors/UnauthorizedError";
|
|
5
|
-
export * from "./errors/codes/JwtErrorCodes";
|
|
6
|
-
export * from "./errors/ForbiddenError";
|
|
7
|
-
export * from "./jwt-utils/JwtHelper";
|
|
8
|
-
export * from "./middlewares/authMiddleware";
|
|
9
|
-
export * from "./middlewares/requireRole";
|
|
10
1
|
export * from "./types/UserRoles";
|
|
11
2
|
export * from "./constants/HttpStatus";
|
|
12
3
|
export * from "./events/AppEvent";
|
|
13
4
|
export * from "./events/schemas/userEventsSchema";
|
|
14
5
|
export * from "./events/CreateEvent";
|
|
15
|
-
export * from "./events/Consumer";
|
|
16
|
-
export * from "./events/Producer";
|
package/build/index.js
CHANGED
|
@@ -14,18 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
// Errors
|
|
18
|
-
__exportStar(require("./errors/AppError"), exports);
|
|
19
|
-
__exportStar(require("./errors/JwtErrors"), exports);
|
|
20
|
-
__exportStar(require("./errors/UnauthenticatedError"), exports);
|
|
21
|
-
__exportStar(require("./errors/UnauthorizedError"), exports);
|
|
22
|
-
__exportStar(require("./errors/codes/JwtErrorCodes"), exports);
|
|
23
|
-
__exportStar(require("./errors/ForbiddenError"), exports);
|
|
24
|
-
// Helpers
|
|
25
|
-
__exportStar(require("./jwt-utils/JwtHelper"), exports);
|
|
26
|
-
// Middlewares
|
|
27
|
-
__exportStar(require("./middlewares/authMiddleware"), exports);
|
|
28
|
-
__exportStar(require("./middlewares/requireRole"), exports);
|
|
29
17
|
// Types
|
|
30
18
|
__exportStar(require("./types/UserRoles"), exports);
|
|
31
19
|
// Constants
|
|
@@ -34,5 +22,3 @@ __exportStar(require("./constants/HttpStatus"), exports);
|
|
|
34
22
|
__exportStar(require("./events/AppEvent"), exports);
|
|
35
23
|
__exportStar(require("./events/schemas/userEventsSchema"), exports);
|
|
36
24
|
__exportStar(require("./events/CreateEvent"), exports);
|
|
37
|
-
__exportStar(require("./events/Consumer"), exports);
|
|
38
|
-
__exportStar(require("./events/Producer"), exports);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
// Errors
|
|
2
|
-
export * from "./errors/AppError";
|
|
3
|
-
export * from "./errors/JwtErrors";
|
|
4
|
-
export * from "./errors/UnauthenticatedError";
|
|
5
|
-
export * from "./errors/UnauthorizedError";
|
|
6
|
-
export * from "./errors/codes/JwtErrorCodes";
|
|
7
|
-
export * from "./errors/ForbiddenError";
|
|
8
|
-
|
|
9
|
-
// Helpers
|
|
10
|
-
export * from "./jwt-utils/JwtHelper";
|
|
11
|
-
|
|
12
|
-
// Middlewares
|
|
13
|
-
export * from "./middlewares/authMiddleware";
|
|
14
|
-
export * from "./middlewares/requireRole";
|
|
15
|
-
|
|
16
1
|
// Types
|
|
17
2
|
export * from "./types/UserRoles";
|
|
18
3
|
|
|
@@ -23,5 +8,3 @@ export * from "./constants/HttpStatus";
|
|
|
23
8
|
export * from "./events/AppEvent";
|
|
24
9
|
export * from "./events/schemas/userEventsSchema";
|
|
25
10
|
export * from "./events/CreateEvent";
|
|
26
|
-
export * from "./events/Consumer";
|
|
27
|
-
export * from "./events/Producer";
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare abstract class AppError extends Error {
|
|
2
|
-
readonly message: string;
|
|
3
|
-
readonly code: string;
|
|
4
|
-
readonly context?: Record<string, unknown> | undefined;
|
|
5
|
-
readonly name: string;
|
|
6
|
-
constructor(message: string, code: string, context?: Record<string, unknown> | undefined);
|
|
7
|
-
abstract toJSON(): object;
|
|
8
|
-
}
|
|
9
|
-
export declare abstract class DomainError extends AppError {
|
|
10
|
-
}
|
|
11
|
-
export declare abstract class InfrastructureError extends AppError {
|
|
12
|
-
}
|
|
13
|
-
export declare abstract class ApplicationError extends AppError {
|
|
14
|
-
}
|
package/build/errors/AppError.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApplicationError = exports.InfrastructureError = exports.DomainError = exports.AppError = void 0;
|
|
4
|
-
class AppError extends Error {
|
|
5
|
-
constructor(message, code, context) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.message = message;
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.context = context;
|
|
10
|
-
this.name = this.constructor.name;
|
|
11
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
exports.AppError = AppError;
|
|
15
|
-
class DomainError extends AppError {
|
|
16
|
-
}
|
|
17
|
-
exports.DomainError = DomainError;
|
|
18
|
-
class InfrastructureError extends AppError {
|
|
19
|
-
}
|
|
20
|
-
exports.InfrastructureError = InfrastructureError;
|
|
21
|
-
class ApplicationError extends AppError {
|
|
22
|
-
}
|
|
23
|
-
exports.ApplicationError = ApplicationError;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ForbiddenError = void 0;
|
|
4
|
-
const AppError_1 = require("./AppError");
|
|
5
|
-
class ForbiddenError extends AppError_1.ApplicationError {
|
|
6
|
-
constructor() {
|
|
7
|
-
super("Forbidden", "FORBIDDEN_ERROR");
|
|
8
|
-
}
|
|
9
|
-
toJSON() {
|
|
10
|
-
return { message: this.message, code: this.code };
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
exports.ForbiddenError = ForbiddenError;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { InfrastructureError } from "./AppError";
|
|
2
|
-
import { JwtErrorCodes } from "./codes/JwtErrorCodes";
|
|
3
|
-
export declare class JwtError extends InfrastructureError {
|
|
4
|
-
constructor(code: keyof typeof JwtErrorCodes);
|
|
5
|
-
toJSON(): object;
|
|
6
|
-
}
|
|
7
|
-
export declare class EmailVerificationJwtVerifyError extends JwtError {
|
|
8
|
-
constructor();
|
|
9
|
-
}
|
|
10
|
-
export declare class RefreshTokenVerifyError extends JwtError {
|
|
11
|
-
constructor();
|
|
12
|
-
}
|
|
13
|
-
export declare class AccessTokenVerifyError extends JwtError {
|
|
14
|
-
constructor();
|
|
15
|
-
}
|
|
16
|
-
export declare class InvalidTokenError extends JwtError {
|
|
17
|
-
constructor();
|
|
18
|
-
}
|
|
19
|
-
export declare class InvalidTokenRoleError extends JwtError {
|
|
20
|
-
constructor();
|
|
21
|
-
}
|
|
22
|
-
export declare class TokenRoleMismatchError extends JwtError {
|
|
23
|
-
constructor();
|
|
24
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TokenRoleMismatchError = exports.InvalidTokenRoleError = exports.InvalidTokenError = exports.AccessTokenVerifyError = exports.RefreshTokenVerifyError = exports.EmailVerificationJwtVerifyError = exports.JwtError = void 0;
|
|
4
|
-
const AppError_1 = require("./AppError");
|
|
5
|
-
const JwtErrorCodes_1 = require("./codes/JwtErrorCodes");
|
|
6
|
-
class JwtError extends AppError_1.InfrastructureError {
|
|
7
|
-
constructor(code) {
|
|
8
|
-
super(JwtErrorCodes_1.JwtErrorCodes[code], code);
|
|
9
|
-
}
|
|
10
|
-
toJSON() {
|
|
11
|
-
return { error: this.name, message: this.message, code: this.code };
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
exports.JwtError = JwtError;
|
|
15
|
-
class EmailVerificationJwtVerifyError extends JwtError {
|
|
16
|
-
constructor() {
|
|
17
|
-
super("EMAIL_VERIFICATION_JWT_VERIFY_ERROR");
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
exports.EmailVerificationJwtVerifyError = EmailVerificationJwtVerifyError;
|
|
21
|
-
class RefreshTokenVerifyError extends JwtError {
|
|
22
|
-
constructor() {
|
|
23
|
-
super("REFRESH_TOKEN_VERIFY_ERROR");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
exports.RefreshTokenVerifyError = RefreshTokenVerifyError;
|
|
27
|
-
class AccessTokenVerifyError extends JwtError {
|
|
28
|
-
constructor() {
|
|
29
|
-
super("ACCESS_TOKEN_VERIFY_ERROR");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
exports.AccessTokenVerifyError = AccessTokenVerifyError;
|
|
33
|
-
class InvalidTokenError extends JwtError {
|
|
34
|
-
constructor() {
|
|
35
|
-
super("INVALID_TOKEN_ERROR");
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
exports.InvalidTokenError = InvalidTokenError;
|
|
39
|
-
class InvalidTokenRoleError extends JwtError {
|
|
40
|
-
constructor() {
|
|
41
|
-
super("INVALID_TOKEN_ROLE_ERROR");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
exports.InvalidTokenRoleError = InvalidTokenRoleError;
|
|
45
|
-
class TokenRoleMismatchError extends JwtError {
|
|
46
|
-
constructor() {
|
|
47
|
-
super("TOKEN_ROLE_MISMATCH_ERROR");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
exports.TokenRoleMismatchError = TokenRoleMismatchError;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { EventName } from "../events/EventMap";
|
|
2
|
-
import { InfrastructureError } from "./AppError";
|
|
3
|
-
export declare class InvalidEventPayloadError extends InfrastructureError {
|
|
4
|
-
constructor(eventName: EventName, errorString: string);
|
|
5
|
-
toJSON(): object;
|
|
6
|
-
}
|
|
7
|
-
export declare class UnknownEventError extends InfrastructureError {
|
|
8
|
-
constructor(eventName: string);
|
|
9
|
-
toJSON(): object;
|
|
10
|
-
}
|
|
11
|
-
export declare class ConsumerUsedBeforeInitializationError extends InfrastructureError {
|
|
12
|
-
constructor();
|
|
13
|
-
toJSON(): object;
|
|
14
|
-
}
|
|
15
|
-
export declare class ProducerUsedBeforeInitializationError extends InfrastructureError {
|
|
16
|
-
constructor();
|
|
17
|
-
toJSON(): object;
|
|
18
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProducerUsedBeforeInitializationError = exports.ConsumerUsedBeforeInitializationError = exports.UnknownEventError = exports.InvalidEventPayloadError = void 0;
|
|
4
|
-
const AppError_1 = require("./AppError");
|
|
5
|
-
const MessageQueueErrorCodes_1 = require("./codes/MessageQueueErrorCodes");
|
|
6
|
-
class InvalidEventPayloadError extends AppError_1.InfrastructureError {
|
|
7
|
-
constructor(eventName, errorString) {
|
|
8
|
-
super(MessageQueueErrorCodes_1.MessageQueueErrorCodes.INVALID_EVENT_PAYLOAD + ` for ${eventName}`, "INVALID_EVENT_PAYLOAD", { zodErrorString: errorString });
|
|
9
|
-
}
|
|
10
|
-
toJSON() {
|
|
11
|
-
return {
|
|
12
|
-
message: this.message,
|
|
13
|
-
code: this.code,
|
|
14
|
-
error: this.context.zodErrorString,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
exports.InvalidEventPayloadError = InvalidEventPayloadError;
|
|
19
|
-
class UnknownEventError extends AppError_1.InfrastructureError {
|
|
20
|
-
constructor(eventName) {
|
|
21
|
-
super(MessageQueueErrorCodes_1.MessageQueueErrorCodes.UNKNOWN_EVENT + eventName, "UNKNOWN_EVENT");
|
|
22
|
-
}
|
|
23
|
-
toJSON() {
|
|
24
|
-
return { message: this.message, code: this.code };
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
exports.UnknownEventError = UnknownEventError;
|
|
28
|
-
class ConsumerUsedBeforeInitializationError extends AppError_1.InfrastructureError {
|
|
29
|
-
constructor() {
|
|
30
|
-
super(MessageQueueErrorCodes_1.MessageQueueErrorCodes.CONSUMER_USED_BEFORE_INITIALIZATION, "CONSUMER_USED_BEFORE_INITIALIZATION");
|
|
31
|
-
}
|
|
32
|
-
toJSON() {
|
|
33
|
-
return { message: this.message, code: this.code };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
exports.ConsumerUsedBeforeInitializationError = ConsumerUsedBeforeInitializationError;
|
|
37
|
-
class ProducerUsedBeforeInitializationError extends AppError_1.InfrastructureError {
|
|
38
|
-
constructor() {
|
|
39
|
-
super(MessageQueueErrorCodes_1.MessageQueueErrorCodes.PRODUCER_USED_BEFORE_INITIALIZATION, "PRODUCER_USED_BEFORE_INITIALIZATION");
|
|
40
|
-
}
|
|
41
|
-
toJSON() {
|
|
42
|
-
return { message: this.message, code: this.code };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
exports.ProducerUsedBeforeInitializationError = ProducerUsedBeforeInitializationError;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UnauthenticatedError = void 0;
|
|
4
|
-
const AppError_1 = require("./AppError");
|
|
5
|
-
class UnauthenticatedError extends AppError_1.ApplicationError {
|
|
6
|
-
constructor() {
|
|
7
|
-
super("Unauthenticated", "USER_UNAUTHENTICATED");
|
|
8
|
-
}
|
|
9
|
-
toJSON() {
|
|
10
|
-
return { name: this.name, message: this.message };
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
exports.UnauthenticatedError = UnauthenticatedError;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UnauthorizedError = void 0;
|
|
4
|
-
const AppError_1 = require("./AppError");
|
|
5
|
-
class UnauthorizedError extends AppError_1.DomainError {
|
|
6
|
-
constructor() {
|
|
7
|
-
super("You are not authorized", "UNAUTHORIZED");
|
|
8
|
-
}
|
|
9
|
-
toJSON() {
|
|
10
|
-
return { error: this.name, message: this.message, code: this.code };
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
exports.UnauthorizedError = UnauthorizedError;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare enum JwtErrorCodes {
|
|
2
|
-
EMAIL_VERIFICATION_JWT_VERIFY_ERROR = "Invalid email verification jwt",
|
|
3
|
-
REFRESH_TOKEN_VERIFY_ERROR = "Invalid refresh token",
|
|
4
|
-
ACCESS_TOKEN_VERIFY_ERROR = "Invalid access token",
|
|
5
|
-
INVALID_TOKEN_ERROR = "Invalid token",
|
|
6
|
-
INVALID_TOKEN_ROLE_ERROR = "Invalid role identifier",
|
|
7
|
-
TOKEN_ROLE_MISMATCH_ERROR = "Role mismatch between payload and header"
|
|
8
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JwtErrorCodes = void 0;
|
|
4
|
-
var JwtErrorCodes;
|
|
5
|
-
(function (JwtErrorCodes) {
|
|
6
|
-
JwtErrorCodes["EMAIL_VERIFICATION_JWT_VERIFY_ERROR"] = "Invalid email verification jwt";
|
|
7
|
-
JwtErrorCodes["REFRESH_TOKEN_VERIFY_ERROR"] = "Invalid refresh token";
|
|
8
|
-
JwtErrorCodes["ACCESS_TOKEN_VERIFY_ERROR"] = "Invalid access token";
|
|
9
|
-
JwtErrorCodes["INVALID_TOKEN_ERROR"] = "Invalid token";
|
|
10
|
-
JwtErrorCodes["INVALID_TOKEN_ROLE_ERROR"] = "Invalid role identifier";
|
|
11
|
-
JwtErrorCodes["TOKEN_ROLE_MISMATCH_ERROR"] = "Role mismatch between payload and header";
|
|
12
|
-
})(JwtErrorCodes || (exports.JwtErrorCodes = JwtErrorCodes = {}));
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const MessageQueueErrorCodes: {
|
|
2
|
-
readonly PRODUCER_USED_BEFORE_INITIALIZATION: "Producer used before initialization!";
|
|
3
|
-
readonly CONSUMER_USED_BEFORE_INITIALIZATION: "Consumer used before initialization!";
|
|
4
|
-
readonly UNKNOWN_EVENT: "Unknown event type";
|
|
5
|
-
readonly INVALID_EVENT_PAYLOAD: "Invalid payload";
|
|
6
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MessageQueueErrorCodes = void 0;
|
|
4
|
-
exports.MessageQueueErrorCodes = {
|
|
5
|
-
PRODUCER_USED_BEFORE_INITIALIZATION: "Producer used before initialization!",
|
|
6
|
-
CONSUMER_USED_BEFORE_INITIALIZATION: "Consumer used before initialization!",
|
|
7
|
-
UNKNOWN_EVENT: "Unknown event type",
|
|
8
|
-
INVALID_EVENT_PAYLOAD: "Invalid payload",
|
|
9
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Channel } from "amqplib";
|
|
2
|
-
import { EventName } from "./EventMap";
|
|
3
|
-
import { AppEvent } from "./AppEvent";
|
|
4
|
-
type EventHandler<T extends EventName> = (event: AppEvent<T>) => Promise<HandlerResult>;
|
|
5
|
-
export declare class Consumer {
|
|
6
|
-
private _channel;
|
|
7
|
-
private _exchange;
|
|
8
|
-
private _initialized;
|
|
9
|
-
private _handlers;
|
|
10
|
-
constructor();
|
|
11
|
-
init: (channel: Channel, exchange: string, serviceName: string, interestedEvents: (string | EventName)[]) => Promise<void>;
|
|
12
|
-
private handleEvent;
|
|
13
|
-
registerHandler: <T extends EventName>(eventName: T, handler: EventHandler<T>) => void;
|
|
14
|
-
}
|
|
15
|
-
interface HandlerResult {
|
|
16
|
-
success: boolean;
|
|
17
|
-
retryable?: boolean;
|
|
18
|
-
}
|
|
19
|
-
export {};
|
package/build/events/Consumer.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Consumer = void 0;
|
|
13
|
-
const EventMap_1 = require("./EventMap");
|
|
14
|
-
const MessageQueueErrors_1 = require("../errors/MessageQueueErrors");
|
|
15
|
-
class Consumer {
|
|
16
|
-
constructor() {
|
|
17
|
-
this._initialized = false;
|
|
18
|
-
this._handlers = new Map();
|
|
19
|
-
this.init = (channel, exchange, serviceName, interestedEvents) => __awaiter(this, void 0, void 0, function* () {
|
|
20
|
-
this._channel = channel;
|
|
21
|
-
this._exchange = exchange;
|
|
22
|
-
yield this._channel.assertExchange(this._exchange, "topic", {
|
|
23
|
-
durable: true,
|
|
24
|
-
});
|
|
25
|
-
const queue = yield this._channel.assertQueue(`${serviceName}_queue`, {
|
|
26
|
-
durable: true,
|
|
27
|
-
});
|
|
28
|
-
yield Promise.all(interestedEvents.map((eventName) => this._channel.bindQueue(queue.queue, this._exchange, eventName)));
|
|
29
|
-
this._channel.consume(queue.queue, this.handleEvent, { noAck: false });
|
|
30
|
-
this._initialized = true;
|
|
31
|
-
});
|
|
32
|
-
this.handleEvent = (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
if (!msg) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const event = JSON.parse(msg.content.toString());
|
|
37
|
-
const eventName = event.eventName;
|
|
38
|
-
// validate using schema
|
|
39
|
-
const schema = EventMap_1.EventSchemas[eventName];
|
|
40
|
-
if (!schema) {
|
|
41
|
-
throw new MessageQueueErrors_1.UnknownEventError(eventName);
|
|
42
|
-
}
|
|
43
|
-
const parseResult = schema.safeParse(event.data);
|
|
44
|
-
if (!parseResult.success) {
|
|
45
|
-
this._channel.nack(msg, false, false);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
// create typed app event
|
|
49
|
-
const appEvent = Object.assign(Object.assign({}, event), { data: parseResult.data });
|
|
50
|
-
try {
|
|
51
|
-
const handler = this._handlers.get(eventName);
|
|
52
|
-
if (!handler) {
|
|
53
|
-
this._channel.ack(msg); // ack if no handler
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
const result = yield handler(appEvent);
|
|
57
|
-
if (result.success) {
|
|
58
|
-
this._channel.ack(msg);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
const requeue = result.retryable;
|
|
62
|
-
this._channel.nack(msg, false, requeue);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
console.log(err);
|
|
67
|
-
this._channel.nack(msg, false, false);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
this.registerHandler = (eventName, handler) => {
|
|
71
|
-
if (!this._initialized) {
|
|
72
|
-
throw new MessageQueueErrors_1.ConsumerUsedBeforeInitializationError();
|
|
73
|
-
}
|
|
74
|
-
this._handlers.set(eventName, handler);
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
exports.Consumer = Consumer;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Channel } from "amqplib";
|
|
2
|
-
import { AnyAppEvent } from "./AppEvent";
|
|
3
|
-
export declare class Producer {
|
|
4
|
-
private _channel;
|
|
5
|
-
private _exchange;
|
|
6
|
-
private _initialized;
|
|
7
|
-
constructor();
|
|
8
|
-
init: (channel: Channel, exchange: string) => Promise<void>;
|
|
9
|
-
publish: (event: AnyAppEvent) => void;
|
|
10
|
-
}
|
package/build/events/Producer.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Producer = void 0;
|
|
13
|
-
const MessageQueueErrors_1 = require("../errors/MessageQueueErrors");
|
|
14
|
-
class Producer {
|
|
15
|
-
constructor() {
|
|
16
|
-
this._initialized = false;
|
|
17
|
-
this.init = (channel, exchange) => __awaiter(this, void 0, void 0, function* () {
|
|
18
|
-
this._channel = channel;
|
|
19
|
-
this._exchange = exchange;
|
|
20
|
-
yield this._channel.assertExchange(this._exchange, "topic", {
|
|
21
|
-
durable: true,
|
|
22
|
-
});
|
|
23
|
-
this._initialized = true;
|
|
24
|
-
});
|
|
25
|
-
this.publish = (event) => {
|
|
26
|
-
if (!this._initialized) {
|
|
27
|
-
throw new MessageQueueErrors_1.ProducerUsedBeforeInitializationError();
|
|
28
|
-
}
|
|
29
|
-
const routingKey = event.eventName;
|
|
30
|
-
const message = Buffer.from(JSON.stringify(event));
|
|
31
|
-
this._channel.publish(this._exchange, routingKey, message, {
|
|
32
|
-
persistent: true,
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
exports.Producer = Producer;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { UserRoles } from "../types/UserRoles";
|
|
2
|
-
export type tokenBody = {
|
|
3
|
-
userId: string;
|
|
4
|
-
email: string;
|
|
5
|
-
role: Exclude<UserRoles, "ADMIN">;
|
|
6
|
-
} | {
|
|
7
|
-
userId: string;
|
|
8
|
-
username: string;
|
|
9
|
-
role: "ADMIN";
|
|
10
|
-
};
|
|
11
|
-
export type JWTPayload = tokenBody & {
|
|
12
|
-
iat: number;
|
|
13
|
-
exp: number;
|
|
14
|
-
};
|
|
15
|
-
export declare class JwtHelper {
|
|
16
|
-
private _AccessSecrets;
|
|
17
|
-
constructor({ userAccessTokenSecret, expertAccessTokenSecret, adminAccessTokenSecret, }: {
|
|
18
|
-
userAccessTokenSecret: string;
|
|
19
|
-
expertAccessTokenSecret: string;
|
|
20
|
-
adminAccessTokenSecret: string;
|
|
21
|
-
});
|
|
22
|
-
verifyAccessToken: (jwtToken: string) => JWTPayload;
|
|
23
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.JwtHelper = void 0;
|
|
7
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
-
const JwtErrors_1 = require("../errors/JwtErrors");
|
|
9
|
-
function isUserRole(role) {
|
|
10
|
-
return ["ADMIN", "EXPERT", "USER"].includes(role);
|
|
11
|
-
}
|
|
12
|
-
class JwtHelper {
|
|
13
|
-
constructor({ userAccessTokenSecret, expertAccessTokenSecret, adminAccessTokenSecret, }) {
|
|
14
|
-
this.verifyAccessToken = (jwtToken) => {
|
|
15
|
-
const decoded = jsonwebtoken_1.default.decode(jwtToken, { complete: true });
|
|
16
|
-
if (!decoded || !decoded.header) {
|
|
17
|
-
throw new JwtErrors_1.InvalidTokenError();
|
|
18
|
-
}
|
|
19
|
-
const header = decoded.header;
|
|
20
|
-
const role = header.kid;
|
|
21
|
-
if (!role || !isUserRole(role)) {
|
|
22
|
-
throw new JwtErrors_1.InvalidTokenRoleError();
|
|
23
|
-
}
|
|
24
|
-
let payload;
|
|
25
|
-
try {
|
|
26
|
-
payload = jsonwebtoken_1.default.verify(jwtToken, this._AccessSecrets[role]);
|
|
27
|
-
}
|
|
28
|
-
catch (err) {
|
|
29
|
-
throw new JwtErrors_1.AccessTokenVerifyError();
|
|
30
|
-
}
|
|
31
|
-
if (!(role === payload.role)) {
|
|
32
|
-
throw new JwtErrors_1.TokenRoleMismatchError();
|
|
33
|
-
}
|
|
34
|
-
return payload;
|
|
35
|
-
};
|
|
36
|
-
this._AccessSecrets = {
|
|
37
|
-
USER: userAccessTokenSecret,
|
|
38
|
-
ADMIN: adminAccessTokenSecret,
|
|
39
|
-
EXPERT: expertAccessTokenSecret,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
exports.JwtHelper = JwtHelper;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AuthMiddleware = void 0;
|
|
4
|
-
const UnauthenticatedError_1 = require("../errors/UnauthenticatedError");
|
|
5
|
-
const JwtHelper_1 = require("../jwt-utils/JwtHelper");
|
|
6
|
-
const JwtErrors_1 = require("../errors/JwtErrors");
|
|
7
|
-
const HttpStatus_1 = require("../constants/HttpStatus");
|
|
8
|
-
class AuthMiddleware {
|
|
9
|
-
constructor(userAccessTokenSecret, expertAccessTokenSecret, adminAccessTokenSecret) {
|
|
10
|
-
this.verify = (req, res, next) => {
|
|
11
|
-
var _a;
|
|
12
|
-
try {
|
|
13
|
-
const token = (_a = req.headers["authorization"]) === null || _a === void 0 ? void 0 : _a.split(" ")[1];
|
|
14
|
-
if (!token) {
|
|
15
|
-
throw new UnauthenticatedError_1.UnauthenticatedError();
|
|
16
|
-
}
|
|
17
|
-
const payload = this._jwtHelper.verifyAccessToken(token);
|
|
18
|
-
req.user = Object.assign(Object.assign({ id: payload.userId }, (payload.role === "ADMIN"
|
|
19
|
-
? { userame: payload.username }
|
|
20
|
-
: { email: payload.email })), { role: payload.role });
|
|
21
|
-
next();
|
|
22
|
-
}
|
|
23
|
-
catch (err) {
|
|
24
|
-
if (err instanceof JwtErrors_1.AccessTokenVerifyError) {
|
|
25
|
-
res
|
|
26
|
-
.status(HttpStatus_1.HttpStatus.UNAUTHORIZED)
|
|
27
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
else if (err instanceof JwtErrors_1.InvalidTokenError) {
|
|
31
|
-
res
|
|
32
|
-
.status(HttpStatus_1.HttpStatus.UNAUTHORIZED)
|
|
33
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
else if (err instanceof UnauthenticatedError_1.UnauthenticatedError) {
|
|
37
|
-
res
|
|
38
|
-
.status(HttpStatus_1.HttpStatus.UNAUTHORIZED)
|
|
39
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
next(err);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
this._jwtHelper = new JwtHelper_1.JwtHelper({
|
|
46
|
-
userAccessTokenSecret,
|
|
47
|
-
expertAccessTokenSecret,
|
|
48
|
-
adminAccessTokenSecret,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
exports.AuthMiddleware = AuthMiddleware;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.requireRole = void 0;
|
|
4
|
-
const ForbiddenError_1 = require("../errors/ForbiddenError");
|
|
5
|
-
const requireRole = (...roles) => {
|
|
6
|
-
return (req, _res, next) => {
|
|
7
|
-
try {
|
|
8
|
-
if (!req.user || !roles.includes(req.user.role)) {
|
|
9
|
-
throw new ForbiddenError_1.ForbiddenError();
|
|
10
|
-
}
|
|
11
|
-
else {
|
|
12
|
-
next();
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
catch (err) {
|
|
16
|
-
next(err);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
exports.requireRole = requireRole;
|
package/src/errors/AppError.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export abstract class AppError extends Error {
|
|
2
|
-
public readonly name: string;
|
|
3
|
-
constructor(
|
|
4
|
-
public readonly message: string,
|
|
5
|
-
public readonly code: string,
|
|
6
|
-
public readonly context?: Record<string, unknown>,
|
|
7
|
-
) {
|
|
8
|
-
super(message);
|
|
9
|
-
this.name = this.constructor.name;
|
|
10
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
abstract toJSON(): object;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export abstract class DomainError extends AppError {}
|
|
17
|
-
|
|
18
|
-
export abstract class InfrastructureError extends AppError {}
|
|
19
|
-
|
|
20
|
-
export abstract class ApplicationError extends AppError {}
|
package/src/errors/JwtErrors.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { InfrastructureError } from "./AppError";
|
|
2
|
-
import { JwtErrorCodes } from "./codes/JwtErrorCodes";
|
|
3
|
-
|
|
4
|
-
export class JwtError extends InfrastructureError {
|
|
5
|
-
constructor(code: keyof typeof JwtErrorCodes) {
|
|
6
|
-
super(JwtErrorCodes[code], code);
|
|
7
|
-
}
|
|
8
|
-
toJSON(): object {
|
|
9
|
-
return { error: this.name, message: this.message, code: this.code };
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class EmailVerificationJwtVerifyError extends JwtError {
|
|
14
|
-
constructor() {
|
|
15
|
-
super("EMAIL_VERIFICATION_JWT_VERIFY_ERROR");
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class RefreshTokenVerifyError extends JwtError {
|
|
20
|
-
constructor() {
|
|
21
|
-
super("REFRESH_TOKEN_VERIFY_ERROR");
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class AccessTokenVerifyError extends JwtError {
|
|
26
|
-
constructor() {
|
|
27
|
-
super("ACCESS_TOKEN_VERIFY_ERROR");
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class InvalidTokenError extends JwtError {
|
|
32
|
-
constructor() {
|
|
33
|
-
super("INVALID_TOKEN_ERROR");
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class InvalidTokenRoleError extends JwtError {
|
|
38
|
-
constructor() {
|
|
39
|
-
super("INVALID_TOKEN_ROLE_ERROR");
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class TokenRoleMismatchError extends JwtError {
|
|
44
|
-
constructor() {
|
|
45
|
-
super("TOKEN_ROLE_MISMATCH_ERROR");
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { EventName } from "../events/EventMap";
|
|
2
|
-
import { InfrastructureError } from "./AppError";
|
|
3
|
-
import { MessageQueueErrorCodes } from "./codes/MessageQueueErrorCodes";
|
|
4
|
-
|
|
5
|
-
export class InvalidEventPayloadError extends InfrastructureError {
|
|
6
|
-
constructor(eventName: EventName, errorString: string) {
|
|
7
|
-
super(
|
|
8
|
-
MessageQueueErrorCodes.INVALID_EVENT_PAYLOAD + ` for ${eventName}`,
|
|
9
|
-
"INVALID_EVENT_PAYLOAD",
|
|
10
|
-
{ zodErrorString: errorString },
|
|
11
|
-
);
|
|
12
|
-
}
|
|
13
|
-
toJSON(): object {
|
|
14
|
-
return {
|
|
15
|
-
message: this.message,
|
|
16
|
-
code: this.code,
|
|
17
|
-
error: this.context!.zodErrorString,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class UnknownEventError extends InfrastructureError {
|
|
23
|
-
constructor(eventName: string) {
|
|
24
|
-
super(MessageQueueErrorCodes.UNKNOWN_EVENT + eventName, "UNKNOWN_EVENT");
|
|
25
|
-
}
|
|
26
|
-
toJSON(): object {
|
|
27
|
-
return { message: this.message, code: this.code };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class ConsumerUsedBeforeInitializationError extends InfrastructureError {
|
|
32
|
-
constructor() {
|
|
33
|
-
super(
|
|
34
|
-
MessageQueueErrorCodes.CONSUMER_USED_BEFORE_INITIALIZATION,
|
|
35
|
-
"CONSUMER_USED_BEFORE_INITIALIZATION",
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
toJSON(): object {
|
|
39
|
-
return { message: this.message, code: this.code };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class ProducerUsedBeforeInitializationError extends InfrastructureError {
|
|
44
|
-
constructor() {
|
|
45
|
-
super(
|
|
46
|
-
MessageQueueErrorCodes.PRODUCER_USED_BEFORE_INITIALIZATION,
|
|
47
|
-
"PRODUCER_USED_BEFORE_INITIALIZATION",
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
toJSON(): object {
|
|
51
|
-
return { message: this.message, code: this.code };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { ApplicationError } from "./AppError";
|
|
2
|
-
|
|
3
|
-
export class UnauthenticatedError extends ApplicationError {
|
|
4
|
-
constructor() {
|
|
5
|
-
super("Unauthenticated", "USER_UNAUTHENTICATED");
|
|
6
|
-
}
|
|
7
|
-
toJSON(): object {
|
|
8
|
-
return { name: this.name, message: this.message };
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { DomainError } from "./AppError";
|
|
2
|
-
|
|
3
|
-
export class UnauthorizedError extends DomainError {
|
|
4
|
-
constructor() {
|
|
5
|
-
super("You are not authorized", "UNAUTHORIZED");
|
|
6
|
-
}
|
|
7
|
-
toJSON(): object {
|
|
8
|
-
return { error: this.name, message: this.message, code: this.code };
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export enum JwtErrorCodes {
|
|
2
|
-
EMAIL_VERIFICATION_JWT_VERIFY_ERROR = "Invalid email verification jwt",
|
|
3
|
-
REFRESH_TOKEN_VERIFY_ERROR = "Invalid refresh token",
|
|
4
|
-
ACCESS_TOKEN_VERIFY_ERROR = "Invalid access token",
|
|
5
|
-
INVALID_TOKEN_ERROR = "Invalid token",
|
|
6
|
-
INVALID_TOKEN_ROLE_ERROR = "Invalid role identifier",
|
|
7
|
-
TOKEN_ROLE_MISMATCH_ERROR = "Role mismatch between payload and header",
|
|
8
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export const MessageQueueErrorCodes = {
|
|
2
|
-
PRODUCER_USED_BEFORE_INITIALIZATION: "Producer used before initialization!",
|
|
3
|
-
CONSUMER_USED_BEFORE_INITIALIZATION: "Consumer used before initialization!",
|
|
4
|
-
UNKNOWN_EVENT: "Unknown event type",
|
|
5
|
-
INVALID_EVENT_PAYLOAD: "Invalid payload",
|
|
6
|
-
} as const;
|
package/src/events/Consumer.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Channel, ConsumeMessage } from "amqplib";
|
|
2
|
-
import { EventName, EventSchemas } from "./EventMap";
|
|
3
|
-
import { AnyAppEvent, AppEvent } from "./AppEvent";
|
|
4
|
-
import {
|
|
5
|
-
ConsumerUsedBeforeInitializationError,
|
|
6
|
-
UnknownEventError,
|
|
7
|
-
} from "../errors/MessageQueueErrors";
|
|
8
|
-
|
|
9
|
-
type EventHandler<T extends EventName> = (
|
|
10
|
-
event: AppEvent<T>,
|
|
11
|
-
) => Promise<HandlerResult>;
|
|
12
|
-
|
|
13
|
-
export class Consumer {
|
|
14
|
-
private _channel!: Channel;
|
|
15
|
-
private _exchange!: string;
|
|
16
|
-
private _initialized: boolean = false;
|
|
17
|
-
private _handlers = new Map<EventName, EventHandler<EventName>>();
|
|
18
|
-
constructor() {}
|
|
19
|
-
|
|
20
|
-
init = async (
|
|
21
|
-
channel: Channel,
|
|
22
|
-
exchange: string,
|
|
23
|
-
serviceName: string,
|
|
24
|
-
interestedEvents: (string | EventName)[], // ex: user.#, payments.subscribed
|
|
25
|
-
) => {
|
|
26
|
-
this._channel = channel;
|
|
27
|
-
this._exchange = exchange;
|
|
28
|
-
await this._channel.assertExchange(this._exchange, "topic", {
|
|
29
|
-
durable: true,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const queue = await this._channel.assertQueue(`${serviceName}_queue`, {
|
|
33
|
-
durable: true,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
await Promise.all(
|
|
37
|
-
interestedEvents.map((eventName) =>
|
|
38
|
-
this._channel.bindQueue(queue.queue, this._exchange, eventName),
|
|
39
|
-
),
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
this._channel.consume(queue.queue, this.handleEvent, { noAck: false });
|
|
43
|
-
|
|
44
|
-
this._initialized = true;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
private handleEvent = async (msg: ConsumeMessage | null) => {
|
|
48
|
-
if (!msg) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const event = JSON.parse(msg.content.toString()) as AnyAppEvent;
|
|
52
|
-
const eventName = event.eventName;
|
|
53
|
-
|
|
54
|
-
// validate using schema
|
|
55
|
-
const schema = EventSchemas[eventName];
|
|
56
|
-
if (!schema) {
|
|
57
|
-
throw new UnknownEventError(eventName);
|
|
58
|
-
}
|
|
59
|
-
const parseResult = schema.safeParse(event.data);
|
|
60
|
-
if (!parseResult.success) {
|
|
61
|
-
this._channel.nack(msg, false, false);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// create typed app event
|
|
66
|
-
const appEvent: AppEvent<typeof eventName> = {
|
|
67
|
-
...event,
|
|
68
|
-
data: parseResult.data,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const handler = this._handlers.get(eventName);
|
|
73
|
-
if (!handler) {
|
|
74
|
-
this._channel.ack(msg); // ack if no handler
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const result = await handler(appEvent);
|
|
79
|
-
|
|
80
|
-
if (result.success) {
|
|
81
|
-
this._channel.ack(msg);
|
|
82
|
-
} else {
|
|
83
|
-
const requeue = result.retryable;
|
|
84
|
-
this._channel.nack(msg, false, requeue);
|
|
85
|
-
}
|
|
86
|
-
} catch (err) {
|
|
87
|
-
console.log(err);
|
|
88
|
-
this._channel.nack(msg, false, false);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
registerHandler = <T extends EventName>(
|
|
93
|
-
eventName: T,
|
|
94
|
-
handler: EventHandler<T>,
|
|
95
|
-
) => {
|
|
96
|
-
if (!this._initialized) {
|
|
97
|
-
throw new ConsumerUsedBeforeInitializationError();
|
|
98
|
-
}
|
|
99
|
-
this._handlers.set(eventName, handler as EventHandler<EventName>);
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
interface HandlerResult {
|
|
104
|
-
success: boolean;
|
|
105
|
-
retryable?: boolean;
|
|
106
|
-
}
|
package/src/events/Producer.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Channel } from "amqplib";
|
|
2
|
-
import { AnyAppEvent } from "./AppEvent";
|
|
3
|
-
import { ProducerUsedBeforeInitializationError } from "../errors/MessageQueueErrors";
|
|
4
|
-
|
|
5
|
-
export class Producer {
|
|
6
|
-
private _channel!: Channel;
|
|
7
|
-
private _exchange!: string;
|
|
8
|
-
private _initialized: boolean = false;
|
|
9
|
-
constructor() {}
|
|
10
|
-
|
|
11
|
-
init = async (channel: Channel, exchange: string) => {
|
|
12
|
-
this._channel = channel;
|
|
13
|
-
this._exchange = exchange;
|
|
14
|
-
await this._channel.assertExchange(this._exchange, "topic", {
|
|
15
|
-
durable: true,
|
|
16
|
-
});
|
|
17
|
-
this._initialized = true;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
publish = (event: AnyAppEvent) => {
|
|
21
|
-
if (!this._initialized) {
|
|
22
|
-
throw new ProducerUsedBeforeInitializationError();
|
|
23
|
-
}
|
|
24
|
-
const routingKey = event.eventName;
|
|
25
|
-
const message = Buffer.from(JSON.stringify(event));
|
|
26
|
-
this._channel.publish(this._exchange, routingKey, message, {
|
|
27
|
-
persistent: true,
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import jwt, { JwtHeader } from "jsonwebtoken";
|
|
2
|
-
import { UserRoles } from "../types/UserRoles";
|
|
3
|
-
import {
|
|
4
|
-
AccessTokenVerifyError,
|
|
5
|
-
InvalidTokenError,
|
|
6
|
-
InvalidTokenRoleError,
|
|
7
|
-
TokenRoleMismatchError,
|
|
8
|
-
} from "../errors/JwtErrors";
|
|
9
|
-
|
|
10
|
-
function isUserRole(role: string): role is UserRoles {
|
|
11
|
-
return ["ADMIN", "EXPERT", "USER"].includes(role);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type tokenBody =
|
|
15
|
-
| {
|
|
16
|
-
userId: string;
|
|
17
|
-
email: string;
|
|
18
|
-
role: Exclude<UserRoles, "ADMIN">;
|
|
19
|
-
}
|
|
20
|
-
| {
|
|
21
|
-
userId: string;
|
|
22
|
-
username: string;
|
|
23
|
-
role: "ADMIN";
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type JWTPayload = tokenBody & {
|
|
27
|
-
iat: number;
|
|
28
|
-
exp: number;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export class JwtHelper {
|
|
32
|
-
private _AccessSecrets: Record<UserRoles, string>;
|
|
33
|
-
constructor({
|
|
34
|
-
userAccessTokenSecret,
|
|
35
|
-
expertAccessTokenSecret,
|
|
36
|
-
adminAccessTokenSecret,
|
|
37
|
-
}: {
|
|
38
|
-
userAccessTokenSecret: string;
|
|
39
|
-
expertAccessTokenSecret: string;
|
|
40
|
-
adminAccessTokenSecret: string;
|
|
41
|
-
}) {
|
|
42
|
-
this._AccessSecrets = {
|
|
43
|
-
USER: userAccessTokenSecret,
|
|
44
|
-
ADMIN: adminAccessTokenSecret,
|
|
45
|
-
EXPERT: expertAccessTokenSecret,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
verifyAccessToken = (jwtToken: string) => {
|
|
50
|
-
const decoded = jwt.decode(jwtToken, { complete: true }) as any;
|
|
51
|
-
if (!decoded || !decoded.header) {
|
|
52
|
-
throw new InvalidTokenError();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const header = decoded.header as JwtHeader & { kid?: string };
|
|
56
|
-
const role = header.kid as UserRoles | undefined;
|
|
57
|
-
|
|
58
|
-
if (!role || !isUserRole(role)) {
|
|
59
|
-
throw new InvalidTokenRoleError();
|
|
60
|
-
}
|
|
61
|
-
let payload: JWTPayload;
|
|
62
|
-
try {
|
|
63
|
-
payload = <JWTPayload>jwt.verify(jwtToken, this._AccessSecrets[role]);
|
|
64
|
-
} catch (err) {
|
|
65
|
-
throw new AccessTokenVerifyError();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!(role === payload.role)) {
|
|
69
|
-
throw new TokenRoleMismatchError();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return payload;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { RequestHandler } from "express";
|
|
2
|
-
import { UnauthenticatedError } from "../errors/UnauthenticatedError";
|
|
3
|
-
import { JwtHelper } from "../jwt-utils/JwtHelper";
|
|
4
|
-
import { AccessTokenVerifyError, InvalidTokenError } from "../errors/JwtErrors";
|
|
5
|
-
import { HttpStatus } from "../constants/HttpStatus";
|
|
6
|
-
|
|
7
|
-
export class AuthMiddleware {
|
|
8
|
-
private _jwtHelper: JwtHelper;
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
userAccessTokenSecret: string,
|
|
12
|
-
expertAccessTokenSecret: string,
|
|
13
|
-
adminAccessTokenSecret: string,
|
|
14
|
-
) {
|
|
15
|
-
this._jwtHelper = new JwtHelper({
|
|
16
|
-
userAccessTokenSecret,
|
|
17
|
-
expertAccessTokenSecret,
|
|
18
|
-
adminAccessTokenSecret,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
verify: RequestHandler = (req, res, next) => {
|
|
23
|
-
try {
|
|
24
|
-
const token = req.headers["authorization"]?.split(" ")[1];
|
|
25
|
-
if (!token) {
|
|
26
|
-
throw new UnauthenticatedError();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const payload = this._jwtHelper.verifyAccessToken(token);
|
|
30
|
-
req.user = {
|
|
31
|
-
id: payload.userId,
|
|
32
|
-
...(payload.role === "ADMIN"
|
|
33
|
-
? { userame: payload.username }
|
|
34
|
-
: { email: payload.email }),
|
|
35
|
-
role: payload.role,
|
|
36
|
-
};
|
|
37
|
-
next();
|
|
38
|
-
} catch (err) {
|
|
39
|
-
if (err instanceof AccessTokenVerifyError) {
|
|
40
|
-
res
|
|
41
|
-
.status(HttpStatus.UNAUTHORIZED)
|
|
42
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
43
|
-
return;
|
|
44
|
-
} else if (err instanceof InvalidTokenError) {
|
|
45
|
-
res
|
|
46
|
-
.status(HttpStatus.UNAUTHORIZED)
|
|
47
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
48
|
-
return;
|
|
49
|
-
} else if (err instanceof UnauthenticatedError) {
|
|
50
|
-
res
|
|
51
|
-
.status(HttpStatus.UNAUTHORIZED)
|
|
52
|
-
.json({ success: false, message: err.message, code: err.code });
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
next(err);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { NextFunction, Request, Response } from "express";
|
|
2
|
-
import { UserRoles } from "../types/UserRoles";
|
|
3
|
-
import { ForbiddenError } from "../errors/ForbiddenError";
|
|
4
|
-
|
|
5
|
-
export const requireRole = (...roles: UserRoles[]) => {
|
|
6
|
-
return (req: Request, _res: Response, next: NextFunction) => {
|
|
7
|
-
try {
|
|
8
|
-
if (!req.user || !roles.includes(req.user.role)) {
|
|
9
|
-
throw new ForbiddenError();
|
|
10
|
-
} else {
|
|
11
|
-
next();
|
|
12
|
-
}
|
|
13
|
-
} catch (err) {
|
|
14
|
-
next(err);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
};
|