plac-micro-common 1.1.13 → 1.2.1
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/dist/http/constants/index.d.ts +1 -0
- package/dist/http/constants/index.js +4 -0
- package/dist/http/decorators/index.d.ts +1 -0
- package/dist/http/decorators/index.js +1 -0
- package/dist/http/decorators/require_permission.decorator.d.ts +1 -0
- package/dist/http/decorators/require_permission.decorator.js +7 -0
- package/dist/http/guards/index.d.ts +1 -0
- package/dist/http/guards/index.js +1 -0
- package/dist/http/guards/permission.guard.d.ts +7 -0
- package/dist/http/guards/permission.guard.js +44 -0
- package/dist/libs/redis/redis.constant.d.ts +13 -1
- package/dist/libs/redis/redis.constant.js +15 -2
- package/dist/libs/redis/redis.module.js +72 -20
- package/dist/libs/redis/redis.service.d.ts +13 -8
- package/dist/libs/redis/redis.service.js +45 -30
- package/dist/types/permission.type.d.ts +14 -6
- package/dist/types/permission.type.js +15 -8
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const REQUIRE_PERMISSIONS_KEY = "require_permissions";
|
|
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./client_ctx.decorator"), exports);
|
|
18
18
|
__exportStar(require("./current_app.decorator"), exports);
|
|
19
19
|
__exportStar(require("./current_app_client.decorator"), exports);
|
|
20
|
+
__exportStar(require("./require_permission.decorator"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const RequirePermissions: (...permissions: string[]) => import("@nestjs/common").CustomDecorator<string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequirePermissions = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
const RequirePermissions = (...permissions) => (0, common_1.SetMetadata)(constants_1.REQUIRE_PERMISSIONS_KEY, permissions);
|
|
7
|
+
exports.RequirePermissions = RequirePermissions;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from "@nestjs/common";
|
|
2
|
+
import { Reflector } from "@nestjs/core";
|
|
3
|
+
export declare class PermissionsGuard implements CanActivate {
|
|
4
|
+
private readonly reflector;
|
|
5
|
+
constructor(reflector: Reflector);
|
|
6
|
+
canActivate(context: ExecutionContext): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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.PermissionsGuard = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const core_1 = require("@nestjs/core");
|
|
15
|
+
const constants_1 = require("../constants");
|
|
16
|
+
let PermissionsGuard = class PermissionsGuard {
|
|
17
|
+
constructor(reflector) {
|
|
18
|
+
this.reflector = reflector;
|
|
19
|
+
}
|
|
20
|
+
canActivate(context) {
|
|
21
|
+
const required = this.reflector.getAllAndOverride(constants_1.REQUIRE_PERMISSIONS_KEY, [context.getHandler(), context.getClass()]);
|
|
22
|
+
// No permissions required => allow
|
|
23
|
+
if (!required || required.length === 0)
|
|
24
|
+
return true;
|
|
25
|
+
const req = context.switchToHttp().getRequest();
|
|
26
|
+
// Must have req.user set by JwtAuthGuard (passport-jwt or custom)
|
|
27
|
+
const user = req?.user;
|
|
28
|
+
if (!user)
|
|
29
|
+
throw new common_1.UnauthorizedException("Missing auth user");
|
|
30
|
+
const userPerms = Array.isArray(user.permissions)
|
|
31
|
+
? user.permissions
|
|
32
|
+
: [];
|
|
33
|
+
// require ALL permissions by default
|
|
34
|
+
const hasAll = required.every((p) => userPerms.includes(p));
|
|
35
|
+
if (!hasAll)
|
|
36
|
+
throw new common_1.ForbiddenException("Insufficient permissions");
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.PermissionsGuard = PermissionsGuard;
|
|
41
|
+
exports.PermissionsGuard = PermissionsGuard = __decorate([
|
|
42
|
+
(0, common_1.Injectable)(),
|
|
43
|
+
__metadata("design:paramtypes", [core_1.Reflector])
|
|
44
|
+
], PermissionsGuard);
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const REDIS_CLIENTS = "REDIS_CLIENTS";
|
|
2
|
+
/**
|
|
3
|
+
* Named client token helper (if you want to inject a specific client directly)
|
|
4
|
+
* Example: @Inject(getRedisClientToken('geo')) private geoRedis: Redis
|
|
5
|
+
*/
|
|
6
|
+
export declare const getRedisClientToken: (name: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Backward compatible tokens:
|
|
9
|
+
* - REDIS_CLIENT is the "main" redis client
|
|
10
|
+
* - REDIS_GEO_CLIENT is the "geo" redis client
|
|
11
|
+
*/
|
|
12
|
+
export declare const REDIS_CLIENT: string;
|
|
13
|
+
export declare const REDIS_GEO_CLIENT: string;
|
|
2
14
|
export type RedisModuleOptions = {
|
|
3
15
|
url?: string;
|
|
4
16
|
host?: string;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.REDIS_CLIENT = void 0;
|
|
4
|
-
exports.
|
|
3
|
+
exports.REDIS_GEO_CLIENT = exports.REDIS_CLIENT = exports.getRedisClientToken = exports.REDIS_CLIENTS = void 0;
|
|
4
|
+
exports.REDIS_CLIENTS = "REDIS_CLIENTS";
|
|
5
|
+
/**
|
|
6
|
+
* Named client token helper (if you want to inject a specific client directly)
|
|
7
|
+
* Example: @Inject(getRedisClientToken('geo')) private geoRedis: Redis
|
|
8
|
+
*/
|
|
9
|
+
const getRedisClientToken = (name) => `REDIS_CLIENT:${name}`;
|
|
10
|
+
exports.getRedisClientToken = getRedisClientToken;
|
|
11
|
+
/**
|
|
12
|
+
* Backward compatible tokens:
|
|
13
|
+
* - REDIS_CLIENT is the "main" redis client
|
|
14
|
+
* - REDIS_GEO_CLIENT is the "geo" redis client
|
|
15
|
+
*/
|
|
16
|
+
exports.REDIS_CLIENT = (0, exports.getRedisClientToken)("main");
|
|
17
|
+
exports.REDIS_GEO_CLIENT = (0, exports.getRedisClientToken)("geo");
|
|
@@ -16,40 +16,92 @@ const config_1 = require("@nestjs/config");
|
|
|
16
16
|
const ioredis_1 = __importDefault(require("ioredis"));
|
|
17
17
|
const redis_constant_1 = require("./redis.constant");
|
|
18
18
|
const redis_service_1 = require("./redis.service");
|
|
19
|
+
function parseNames(v) {
|
|
20
|
+
// default includes geo for backward compatibility with your existing code
|
|
21
|
+
const raw = (v ?? "main,geo")
|
|
22
|
+
.split(",")
|
|
23
|
+
.map((s) => s.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
// ensure unique
|
|
26
|
+
return Array.from(new Set(raw));
|
|
27
|
+
}
|
|
28
|
+
function upper(name) {
|
|
29
|
+
return name.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
|
|
30
|
+
}
|
|
19
31
|
let RedisModule = RedisModule_1 = class RedisModule {
|
|
20
32
|
static forRootAsync() {
|
|
21
33
|
return {
|
|
22
34
|
module: RedisModule_1,
|
|
23
35
|
imports: [config_1.ConfigModule],
|
|
24
36
|
providers: [
|
|
37
|
+
// 1) Build ALL clients from env and store as a map
|
|
25
38
|
{
|
|
26
|
-
provide: redis_constant_1.
|
|
39
|
+
provide: redis_constant_1.REDIS_CLIENTS,
|
|
27
40
|
inject: [config_1.ConfigService],
|
|
28
41
|
useFactory: (config) => {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
const names = parseNames(config.get("REDIS_NAMES"));
|
|
43
|
+
const baseUrl = config.get("REDIS_URL");
|
|
44
|
+
const baseHost = config.get("REDIS_HOST");
|
|
45
|
+
const basePort = config.get("REDIS_PORT");
|
|
46
|
+
const basePassword = config.get("REDIS_PASSWORD") || undefined;
|
|
47
|
+
const baseDb = config.get("REDIS_DB") ?? 0;
|
|
48
|
+
const baseKeyPrefix = config.get("REDIS_KEY_PREFIX") || undefined;
|
|
49
|
+
const map = {};
|
|
50
|
+
for (const name of names) {
|
|
51
|
+
const N = upper(name);
|
|
52
|
+
const url = config.get(`REDIS_${N}_URL`) ?? baseUrl;
|
|
53
|
+
const host = config.get(`REDIS_${N}_HOST`) ?? baseHost;
|
|
54
|
+
const port = config.get(`REDIS_${N}_PORT`) ?? basePort;
|
|
55
|
+
const password = config.get(`REDIS_${N}_PASSWORD`) ?? basePassword;
|
|
56
|
+
const db = config.get(`REDIS_${N}_DB`) ?? baseDb;
|
|
57
|
+
const keyPrefix = config.get(`REDIS_${N}_KEY_PREFIX`) ?? baseKeyPrefix;
|
|
58
|
+
const client = url
|
|
59
|
+
? new ioredis_1.default(url, { keyPrefix })
|
|
60
|
+
: new ioredis_1.default({
|
|
61
|
+
host,
|
|
62
|
+
port,
|
|
63
|
+
password,
|
|
64
|
+
db,
|
|
65
|
+
keyPrefix,
|
|
66
|
+
});
|
|
67
|
+
client.on("error", (err) => {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.error(`[redis:${name}] error:`, err?.message || err);
|
|
40
70
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// eslint-disable-next-line no-console
|
|
45
|
-
console.error("[redis] error:", err?.message || err);
|
|
46
|
-
});
|
|
47
|
-
return client;
|
|
71
|
+
map[name] = client;
|
|
72
|
+
}
|
|
73
|
+
return map;
|
|
48
74
|
},
|
|
49
75
|
},
|
|
76
|
+
// 2) Provide each named token for DI (optional but useful)
|
|
77
|
+
// e.g. @Inject(getRedisClientToken('geo')) geoRedis: Redis
|
|
78
|
+
{
|
|
79
|
+
provide: (0, redis_constant_1.getRedisClientToken)("main"),
|
|
80
|
+
inject: [redis_constant_1.REDIS_CLIENTS],
|
|
81
|
+
useFactory: (clients) => {
|
|
82
|
+
if (!clients.main)
|
|
83
|
+
throw new Error(`[redis] missing client "main" (check REDIS_NAMES)`);
|
|
84
|
+
return clients.main;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
provide: (0, redis_constant_1.getRedisClientToken)("geo"),
|
|
89
|
+
inject: [redis_constant_1.REDIS_CLIENTS],
|
|
90
|
+
useFactory: (clients) => {
|
|
91
|
+
if (!clients.geo)
|
|
92
|
+
throw new Error(`[redis] missing client "geo" (check REDIS_NAMES)`);
|
|
93
|
+
return clients.geo;
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
// 3) Service uses the map; you can use any client name dynamically
|
|
97
|
+
redis_service_1.RedisService,
|
|
98
|
+
],
|
|
99
|
+
exports: [
|
|
100
|
+
redis_constant_1.REDIS_CLIENTS,
|
|
50
101
|
redis_service_1.RedisService,
|
|
102
|
+
(0, redis_constant_1.getRedisClientToken)("main"),
|
|
103
|
+
(0, redis_constant_1.getRedisClientToken)("geo"),
|
|
51
104
|
],
|
|
52
|
-
exports: [redis_constant_1.REDIS_CLIENT, redis_service_1.RedisService],
|
|
53
105
|
};
|
|
54
106
|
}
|
|
55
107
|
};
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { OnModuleDestroy } from "@nestjs/common";
|
|
2
2
|
import { Redis } from "ioredis";
|
|
3
|
+
type RedisClientMap = Record<string, Redis>;
|
|
3
4
|
export declare class RedisService implements OnModuleDestroy {
|
|
4
|
-
private readonly
|
|
5
|
-
constructor(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
private readonly clients;
|
|
6
|
+
constructor(clients: RedisClientMap);
|
|
7
|
+
private pick;
|
|
8
|
+
get(key: string, clientName?: string): Promise<string | null>;
|
|
9
|
+
del(key: string, clientName?: string): Promise<number>;
|
|
10
|
+
exists(key: string, clientName?: string): Promise<number>;
|
|
11
|
+
client(clientName?: string): Redis;
|
|
12
|
+
getJson<T>(key: string, clientName?: string): Promise<T | null>;
|
|
13
|
+
setJson(key: string, value: unknown, ttlSeconds?: number, clientName?: string): Promise<"OK">;
|
|
14
|
+
getGeoJson<T>(key: string): Promise<T | null>;
|
|
15
|
+
setGeoJson(key: string, value: unknown, ttlSeconds?: number): Promise<"OK">;
|
|
12
16
|
onModuleDestroy(): Promise<void>;
|
|
13
17
|
}
|
|
18
|
+
export {};
|
|
@@ -14,25 +14,35 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.RedisService = void 0;
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
|
-
const ioredis_1 = require("ioredis");
|
|
18
17
|
const redis_constant_1 = require("./redis.constant");
|
|
19
18
|
let RedisService = class RedisService {
|
|
20
|
-
constructor(
|
|
21
|
-
this.
|
|
19
|
+
constructor(clients) {
|
|
20
|
+
this.clients = clients;
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
pick(name = "main") {
|
|
23
|
+
const client = this.clients[name];
|
|
24
|
+
if (!client) {
|
|
25
|
+
const available = Object.keys(this.clients).join(", ");
|
|
26
|
+
throw new Error(`[redis] client "${name}" not found. Available: ${available}`);
|
|
27
|
+
}
|
|
28
|
+
return client;
|
|
29
|
+
}
|
|
30
|
+
// -------------------- RAW --------------------
|
|
31
|
+
get(key, clientName = "main") {
|
|
32
|
+
return this.pick(clientName).get(key);
|
|
26
33
|
}
|
|
27
|
-
del(key) {
|
|
28
|
-
return this.
|
|
34
|
+
del(key, clientName = "main") {
|
|
35
|
+
return this.pick(clientName).del(key);
|
|
29
36
|
}
|
|
30
|
-
exists(key) {
|
|
31
|
-
return this.
|
|
37
|
+
exists(key, clientName = "main") {
|
|
38
|
+
return this.pick(clientName).exists(key);
|
|
32
39
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
client(clientName = "main") {
|
|
41
|
+
return this.pick(clientName);
|
|
42
|
+
}
|
|
43
|
+
// -------------------- JSON --------------------
|
|
44
|
+
async getJson(key, clientName = "main") {
|
|
45
|
+
const val = await this.pick(clientName).get(key);
|
|
36
46
|
if (!val)
|
|
37
47
|
return null;
|
|
38
48
|
try {
|
|
@@ -42,31 +52,36 @@ let RedisService = class RedisService {
|
|
|
42
52
|
return null;
|
|
43
53
|
}
|
|
44
54
|
}
|
|
45
|
-
async setJson(key, value, ttlSeconds) {
|
|
55
|
+
async setJson(key, value, ttlSeconds, clientName = "main") {
|
|
46
56
|
const payload = JSON.stringify(value);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return
|
|
57
|
+
const c = this.pick(clientName);
|
|
58
|
+
if (ttlSeconds && ttlSeconds > 0)
|
|
59
|
+
return c.set(key, payload, "EX", ttlSeconds);
|
|
60
|
+
return c.set(key, payload);
|
|
51
61
|
}
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
return this.
|
|
62
|
+
// Backward-compat convenience (optional)
|
|
63
|
+
async getGeoJson(key) {
|
|
64
|
+
return this.getJson(key, "geo");
|
|
65
|
+
}
|
|
66
|
+
async setGeoJson(key, value, ttlSeconds) {
|
|
67
|
+
return this.setJson(key, value, ttlSeconds, "geo");
|
|
55
68
|
}
|
|
56
69
|
async onModuleDestroy() {
|
|
57
|
-
// Graceful shutdown
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
// Graceful shutdown for ALL clients
|
|
71
|
+
const list = Object.values(this.clients);
|
|
72
|
+
for (const c of list) {
|
|
73
|
+
try {
|
|
74
|
+
await c.quit();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
c.disconnect();
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
81
|
};
|
|
67
82
|
exports.RedisService = RedisService;
|
|
68
83
|
exports.RedisService = RedisService = __decorate([
|
|
69
84
|
(0, common_1.Injectable)(),
|
|
70
|
-
__param(0, (0, common_1.Inject)(redis_constant_1.
|
|
71
|
-
__metadata("design:paramtypes", [
|
|
85
|
+
__param(0, (0, common_1.Inject)(redis_constant_1.REDIS_CLIENTS)),
|
|
86
|
+
__metadata("design:paramtypes", [Object])
|
|
72
87
|
], RedisService);
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
export declare enum PermissionAction {
|
|
2
|
+
Approve = "approve",
|
|
2
3
|
Create = "create",
|
|
4
|
+
Delete = "delete",
|
|
5
|
+
Export = "export",
|
|
3
6
|
Read = "read",
|
|
4
|
-
Update = "update"
|
|
5
|
-
Delete = "delete"
|
|
7
|
+
Update = "update"
|
|
6
8
|
}
|
|
7
|
-
export declare
|
|
8
|
-
Permission
|
|
9
|
-
Quotation
|
|
10
|
-
User
|
|
9
|
+
export declare const PermissionResource: {
|
|
10
|
+
readonly Permission: "permission";
|
|
11
|
+
readonly Quotation: "quotation";
|
|
12
|
+
readonly User: "user";
|
|
13
|
+
};
|
|
14
|
+
export type PermissionResource = (typeof PermissionResource)[keyof typeof PermissionResource];
|
|
15
|
+
export declare enum PermissionModule {
|
|
16
|
+
Admin = "admin",
|
|
17
|
+
Claim = "claim",
|
|
18
|
+
Policy = "policy"
|
|
11
19
|
}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PermissionResource = exports.PermissionAction = void 0;
|
|
3
|
+
exports.PermissionModule = exports.PermissionResource = exports.PermissionAction = void 0;
|
|
4
4
|
var PermissionAction;
|
|
5
5
|
(function (PermissionAction) {
|
|
6
|
+
PermissionAction["Approve"] = "approve";
|
|
6
7
|
PermissionAction["Create"] = "create";
|
|
8
|
+
PermissionAction["Delete"] = "delete";
|
|
9
|
+
PermissionAction["Export"] = "export";
|
|
7
10
|
PermissionAction["Read"] = "read";
|
|
8
11
|
PermissionAction["Update"] = "update";
|
|
9
|
-
PermissionAction["Delete"] = "delete";
|
|
10
12
|
})(PermissionAction || (exports.PermissionAction = PermissionAction = {}));
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
exports.PermissionResource = {
|
|
14
|
+
Permission: "permission",
|
|
15
|
+
Quotation: "quotation",
|
|
16
|
+
User: "user",
|
|
17
|
+
};
|
|
18
|
+
var PermissionModule;
|
|
19
|
+
(function (PermissionModule) {
|
|
20
|
+
PermissionModule["Admin"] = "admin";
|
|
21
|
+
PermissionModule["Claim"] = "claim";
|
|
22
|
+
PermissionModule["Policy"] = "policy";
|
|
23
|
+
})(PermissionModule || (exports.PermissionModule = PermissionModule = {}));
|