@flusys/nestjs-shared 9.1.1 → 9.2.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/README.md +119 -18
- package/classes/api-controller.class.d.ts +1 -0
- package/classes/api-service.class.d.ts +7 -2
- package/classes/hybrid-cache.class.d.ts +17 -4
- package/constants/index.d.ts +1 -0
- package/constants/permissions.d.ts +9 -0
- package/fesm/183.js +7 -7
- package/fesm/47.js +1520 -0
- package/fesm/470.js +333 -382
- package/fesm/667.js +17 -17
- package/fesm/681.js +326 -129
- package/fesm/{948.js → 997.js} +45 -23
- package/fesm/chunks/123.js +17 -9
- package/fesm/chunks/37.js +5 -5
- package/fesm/classes/index.js +4 -3
- package/fesm/constants/index.js +18 -7
- package/fesm/decorators/index.js +120 -39
- package/fesm/dtos/index.js +1 -1
- package/fesm/entities/index.js +8 -8
- package/fesm/enums/index.js +2 -2
- package/fesm/exceptions/index.js +12 -12
- package/fesm/guards/index.js +201 -68
- package/fesm/index.js +95 -42
- package/fesm/interceptors/index.js +290 -590
- package/fesm/interfaces/index.js +97 -8
- package/fesm/middlewares/index.js +4 -4
- package/fesm/modules/index.js +2 -2
- package/fesm/pipes/index.js +8 -8
- package/fesm/utils/index.js +150 -478
- package/interceptors/idempotency.interceptor.d.ts +14 -2
- package/interceptors/slug.interceptor.d.ts +1 -0
- package/interfaces/expression.interface.d.ts +45 -0
- package/interfaces/index.d.ts +1 -0
- package/interfaces/permission-action-registry.interface.d.ts +1 -0
- package/interfaces/permission.interface.d.ts +1 -0
- package/modules/shared-permission-cache/shared-permission-cache.service.d.ts +3 -1
- package/modules/utils/utils.service.d.ts +6 -6
- package/package.json +3 -2
- package/utils/date-time.util.d.ts +0 -1
- package/utils/event-pattern.util.d.ts +1 -0
- package/utils/expression.util.d.ts +35 -0
- package/utils/index.d.ts +2 -0
- package/utils/permission-cache-key.util.d.ts +3 -0
- package/utils/query-helpers.util.d.ts +2 -2
- package/utils/safe-regex.util.d.ts +10 -0
- package/fesm/270.js +0 -659
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as __rspack_external__flusys_nestjs_core_config_197fa0a9 from "@flusys/nestjs-core/config";
|
|
2
|
-
import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
|
|
3
1
|
import * as __rspack_external_crypto from "crypto";
|
|
4
2
|
import * as __rspack_external__keyv_redis_139d03ca from "@keyv/redis";
|
|
5
3
|
import * as __rspack_external_cacheable from "cacheable";
|
|
@@ -9,7 +7,7 @@ import * as __rspack_external_rxjs_operators_2eaa0997 from "rxjs/operators";
|
|
|
9
7
|
export const __rspack_esm_id = 971;
|
|
10
8
|
export const __rspack_esm_ids = [971];
|
|
11
9
|
export const __webpack_modules__ = {
|
|
12
|
-
|
|
10
|
+
5375(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
13
11
|
|
|
14
12
|
// EXPORTS
|
|
15
13
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -17,25 +15,41 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
17
15
|
});
|
|
18
16
|
|
|
19
17
|
// EXTERNAL MODULE: external "@flusys/nestjs-core/config"
|
|
20
|
-
var config_ = __webpack_require__(
|
|
18
|
+
var config_ = __webpack_require__(8307);
|
|
21
19
|
;// CONCATENATED MODULE: external "@keyv/redis"
|
|
22
20
|
|
|
23
21
|
;// CONCATENATED MODULE: external "cacheable"
|
|
24
22
|
|
|
25
23
|
;// CONCATENATED MODULE: external "keyv"
|
|
26
24
|
|
|
25
|
+
// EXTERNAL MODULE: external "node:crypto"
|
|
26
|
+
var external_node_crypto_ = __webpack_require__(2561);
|
|
27
27
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/hybrid-cache.class.ts
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
|
|
33
|
+
const RAW_KEY_PREFIX = 'flusys';
|
|
34
|
+
const STAMP_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
35
|
+
/**
|
|
36
|
+
* L1 in-process memory + L2 Redis, chosen by `USE_CACHE_LABEL` (memory | redis | hybrid).
|
|
37
|
+
*
|
|
38
|
+
* Plain `get`/`set` may be served by L1, which other instances cannot invalidate, so a value
|
|
39
|
+
* read that way must be immutable for its key - which is what version stamps give: data keys
|
|
40
|
+
* embed the current stamp, and invalidation moves the stamp instead of deleting entries.
|
|
41
|
+
* Stamps and claims live outside Keyv so they can be set atomically (Redis `SET NX`).
|
|
42
|
+
*/ class HybridCache {
|
|
43
|
+
mode;
|
|
44
|
+
defaultTtl;
|
|
33
45
|
memory;
|
|
34
46
|
redis;
|
|
47
|
+
redisStore;
|
|
48
|
+
localAtomic;
|
|
35
49
|
constructor(memoryTtl = 60 * 1000, memorySize = 5000){
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
50
|
+
this.mode = config_.envConfig.tryGetValue('USE_CACHE_LABEL', false) || 'memory';
|
|
51
|
+
this.defaultTtl = memoryTtl;
|
|
52
|
+
if (this.mode === 'memory' || this.mode === 'hybrid') {
|
|
39
53
|
this.memory = new __rspack_external_keyv["default"]({
|
|
40
54
|
store: new __rspack_external_cacheable.CacheableMemory({
|
|
41
55
|
ttl: memoryTtl,
|
|
@@ -43,35 +57,51 @@ class HybridCache {
|
|
|
43
57
|
})
|
|
44
58
|
});
|
|
45
59
|
}
|
|
46
|
-
if (
|
|
60
|
+
if (this.mode === 'redis' || this.mode === 'hybrid') {
|
|
61
|
+
this.redisStore = new __rspack_external__keyv_redis_139d03ca["default"](config_.envConfig.getRedisUrl());
|
|
47
62
|
this.redis = new __rspack_external_keyv["default"]({
|
|
48
|
-
store:
|
|
63
|
+
store: this.redisStore
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
// Stamps and claims must never be LRU-evicted while still referenced
|
|
67
|
+
this.localAtomic = new __rspack_external_cacheable.CacheableMemory({
|
|
68
|
+
ttl: STAMP_TTL_MS,
|
|
69
|
+
lruSize: 0,
|
|
70
|
+
checkInterval: 60_000
|
|
49
71
|
});
|
|
50
72
|
}
|
|
51
73
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
getMode() {
|
|
75
|
+
return this.mode;
|
|
76
|
+
}
|
|
77
|
+
async get(key, options = {}) {
|
|
78
|
+
const useMemory = this.memory && !(options.skipMemory && this.redis);
|
|
79
|
+
if (useMemory) {
|
|
55
80
|
const value = await this.memory.get(key);
|
|
56
81
|
if (value !== undefined) return value;
|
|
57
82
|
}
|
|
58
|
-
// Fallback to redis
|
|
59
83
|
if (this.redis) {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
84
|
+
const raw = await this.redis.get(key, {
|
|
85
|
+
raw: true
|
|
86
|
+
});
|
|
87
|
+
if (raw === undefined) return undefined;
|
|
88
|
+
if (useMemory) {
|
|
89
|
+
// Never let the L1 copy outlive the Redis entry (time-bound values such as permissions)
|
|
90
|
+
const remaining = raw.expires ? raw.expires - Date.now() : this.defaultTtl;
|
|
91
|
+
if (remaining > 0) await this.memory.set(key, raw.value, Math.min(remaining, this.defaultTtl));
|
|
64
92
|
}
|
|
65
|
-
return value;
|
|
93
|
+
return raw.value;
|
|
66
94
|
}
|
|
67
95
|
return undefined;
|
|
68
96
|
}
|
|
69
|
-
async set(key, value, ttl) {
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
async set(key, value, ttl, options = {}) {
|
|
98
|
+
const effectiveTtl = ttl ?? this.defaultTtl;
|
|
99
|
+
const useMemory = this.memory && !(options.skipMemory && this.redis);
|
|
100
|
+
if (useMemory) {
|
|
101
|
+
await this.memory.set(key, value, effectiveTtl);
|
|
72
102
|
}
|
|
73
103
|
if (this.redis) {
|
|
74
|
-
await this.redis.set(key, value,
|
|
104
|
+
await this.redis.set(key, value, effectiveTtl);
|
|
75
105
|
}
|
|
76
106
|
}
|
|
77
107
|
async del(key) {
|
|
@@ -82,460 +112,86 @@ class HybridCache {
|
|
|
82
112
|
await this.redis.delete(key);
|
|
83
113
|
}
|
|
84
114
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
/**
|
|
116
|
+
* The current version stamp for `name`, creating one when absent. A missing stamp is always
|
|
117
|
+
* replaced by a fresh random one - never a fixed default - so entries cached under a stamp that
|
|
118
|
+
* expired or was lost can never become current again.
|
|
119
|
+
*/ async getStamp(name) {
|
|
120
|
+
const key = this.rawKey('stamp', name);
|
|
121
|
+
if (this.localAtomic) {
|
|
122
|
+
let stamp = this.localAtomic.get(key);
|
|
123
|
+
if (!stamp) {
|
|
124
|
+
stamp = (0,external_node_crypto_.randomUUID)();
|
|
125
|
+
this.localAtomic.set(key, stamp);
|
|
126
|
+
}
|
|
127
|
+
return stamp;
|
|
88
128
|
}
|
|
129
|
+
const client = await this.redisStore.getClient();
|
|
130
|
+
const existing = await client.get(key);
|
|
131
|
+
if (existing) return String(existing);
|
|
132
|
+
const candidate = (0,external_node_crypto_.randomUUID)();
|
|
133
|
+
await client.set(key, candidate, {
|
|
134
|
+
NX: true,
|
|
135
|
+
PX: STAMP_TTL_MS
|
|
136
|
+
});
|
|
137
|
+
// A key evicted between SET NX and GET must not turn into the fixed stamp "null"
|
|
138
|
+
return String(await client.get(key) ?? candidate);
|
|
89
139
|
}
|
|
90
|
-
async
|
|
91
|
-
|
|
92
|
-
|
|
140
|
+
/** Moves the stamp for `name`, orphaning every entry cached under the previous one on all instances */ async bumpStamp(name) {
|
|
141
|
+
const key = this.rawKey('stamp', name);
|
|
142
|
+
if (this.localAtomic) {
|
|
143
|
+
this.localAtomic.set(key, (0,external_node_crypto_.randomUUID)());
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const client = await this.redisStore.getClient();
|
|
147
|
+
await client.set(key, (0,external_node_crypto_.randomUUID)(), {
|
|
148
|
+
PX: STAMP_TTL_MS
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** Atomically claims `name` for `ttl` ms; true only for the first caller while the claim lives */ async claim(name, ttl) {
|
|
152
|
+
const key = this.rawKey('claim', name);
|
|
153
|
+
if (this.localAtomic) {
|
|
154
|
+
if (this.localAtomic.has(key)) return false;
|
|
155
|
+
this.localAtomic.set(key, true, ttl);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
const client = await this.redisStore.getClient();
|
|
159
|
+
return await client.set(key, '1', {
|
|
160
|
+
NX: true,
|
|
161
|
+
PX: ttl
|
|
162
|
+
}) !== null;
|
|
163
|
+
}
|
|
164
|
+
async releaseClaim(name) {
|
|
165
|
+
const key = this.rawKey('claim', name);
|
|
166
|
+
if (this.localAtomic) {
|
|
167
|
+
this.localAtomic.delete(key);
|
|
168
|
+
return;
|
|
93
169
|
}
|
|
170
|
+
const client = await this.redisStore.getClient();
|
|
171
|
+
await client.del(key);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Reads and removes a one-time value; only one caller across all instances ever receives it.
|
|
175
|
+
* The claim is per value, so a fresh value later stored under the same key (a resent code)
|
|
176
|
+
* can be taken again while the claim on the consumed one is still alive.
|
|
177
|
+
*/ async take(key, ttl) {
|
|
178
|
+
const value = await this.get(key, {
|
|
179
|
+
skipMemory: true
|
|
180
|
+
});
|
|
181
|
+
if (value === undefined) return undefined;
|
|
182
|
+
const digest = (0,external_node_crypto_.createHash)('sha256').update(JSON.stringify(value) ?? '').digest('hex');
|
|
183
|
+
if (!await this.claim(`take:${key}:${digest}`, ttl)) return undefined;
|
|
184
|
+
await this.del(key);
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
rawKey(kind, name) {
|
|
188
|
+
return `${RAW_KEY_PREFIX}:${kind}:${name}`;
|
|
94
189
|
}
|
|
95
190
|
}
|
|
96
191
|
|
|
97
192
|
|
|
98
193
|
},
|
|
99
|
-
|
|
100
|
-
/* import */ var _permissions_js__rspack_import_0 = __webpack_require__(975);
|
|
101
|
-
/* import */ var _message_keys_js__rspack_import_1 = __webpack_require__(389);
|
|
102
|
-
// Metadata keys
|
|
103
|
-
const IS_PUBLIC_KEY = 'isPublic';
|
|
104
|
-
const PERMISSIONS_KEY = 'permissions';
|
|
105
|
-
const DOMAIN_EVENT_HANDLER_KEY = 'domainEventHandler';
|
|
106
|
-
// Injection tokens
|
|
107
|
-
const CACHE_INSTANCE = 'CACHE_INSTANCE';
|
|
108
|
-
const PERMISSION_GUARD_CONFIG = 'PERMISSION_GUARD_CONFIG';
|
|
109
|
-
const EVENT_BUS_INSTANCE = 'EVENT_BUS_INSTANCE';
|
|
110
|
-
const EVENT_BUS_MODULE_OPTIONS = 'EVENT_BUS_MODULE_OPTIONS';
|
|
111
|
-
// Header names
|
|
112
|
-
const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
|
|
113
|
-
const REQUEST_ID_HEADER = 'x-request-id';
|
|
114
|
-
const CLIENT_TYPE_HEADER = 'x-client-type';
|
|
115
|
-
// Cache key prefixes
|
|
116
|
-
const PERMISSIONS_CACHE_PREFIX = 'my-permissions';
|
|
117
|
-
const IDEMPOTENCY_CACHE_PREFIX = 'idempotency';
|
|
118
|
-
// Event bus defaults
|
|
119
|
-
const DEFAULT_EVENT_EXCHANGE = 'flusys.events';
|
|
120
|
-
const DEFAULT_EVENT_TOPIC = 'flusys.domain-events';
|
|
121
|
-
const DEFAULT_EVENT_SERVICE_NAME = 'flusys';
|
|
122
|
-
// Permission codes
|
|
123
|
-
|
|
124
|
-
// Message keys for localization
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
128
|
-
BC: () => (/* reexport safe */ _permissions_js__rspack_import_0.BC),
|
|
129
|
-
Bz: () => (/* reexport safe */ _permissions_js__rspack_import_0.Bz),
|
|
130
|
-
DP: () => (/* reexport safe */ _permissions_js__rspack_import_0.DP),
|
|
131
|
-
Em: () => (/* reexport safe */ _permissions_js__rspack_import_0.Em),
|
|
132
|
-
G0: () => (/* reexport safe */ _permissions_js__rspack_import_0.G0),
|
|
133
|
-
GH: () => (/* reexport safe */ _permissions_js__rspack_import_0.GH),
|
|
134
|
-
GT: () => (/* reexport safe */ _permissions_js__rspack_import_0.GT),
|
|
135
|
-
Jj: () => (/* reexport safe */ _permissions_js__rspack_import_0.Jj),
|
|
136
|
-
N3: () => (/* reexport safe */ _permissions_js__rspack_import_0.N3),
|
|
137
|
-
ON: () => (/* reexport safe */ _permissions_js__rspack_import_0.ON),
|
|
138
|
-
P0: () => (/* reexport safe */ _permissions_js__rspack_import_0.P0),
|
|
139
|
-
Q5: () => (/* reexport safe */ _permissions_js__rspack_import_0.Q5),
|
|
140
|
-
S6: () => (/* reexport safe */ _permissions_js__rspack_import_0.S6),
|
|
141
|
-
T: () => (/* reexport safe */ _permissions_js__rspack_import_0.T),
|
|
142
|
-
UB: () => (/* reexport safe */ _permissions_js__rspack_import_0.UB),
|
|
143
|
-
UG: () => (/* reexport safe */ _permissions_js__rspack_import_0.UG),
|
|
144
|
-
UU: () => (/* reexport safe */ _message_keys_js__rspack_import_1.UU),
|
|
145
|
-
Ub: () => (/* reexport safe */ _permissions_js__rspack_import_0.Ub),
|
|
146
|
-
V0: () => (/* reexport safe */ _permissions_js__rspack_import_0.V0),
|
|
147
|
-
Wc: () => (/* reexport safe */ _permissions_js__rspack_import_0.Wc),
|
|
148
|
-
Y3: () => (/* reexport safe */ _permissions_js__rspack_import_0.Y3),
|
|
149
|
-
Y7: () => (/* reexport safe */ _permissions_js__rspack_import_0.Y7),
|
|
150
|
-
_X: () => (/* reexport safe */ _permissions_js__rspack_import_0._X),
|
|
151
|
-
aO: () => (/* reexport safe */ _permissions_js__rspack_import_0.aO),
|
|
152
|
-
aT: () => (/* reexport safe */ _permissions_js__rspack_import_0.aT),
|
|
153
|
-
fS: () => (/* reexport safe */ _permissions_js__rspack_import_0.fS),
|
|
154
|
-
hg: () => (/* reexport safe */ _message_keys_js__rspack_import_1.hg),
|
|
155
|
-
kA: () => (/* reexport safe */ _permissions_js__rspack_import_0.kA),
|
|
156
|
-
kd: () => (/* reexport safe */ _permissions_js__rspack_import_0.kd),
|
|
157
|
-
l3: () => (/* reexport safe */ _permissions_js__rspack_import_0.l3),
|
|
158
|
-
mK: () => (/* reexport safe */ _message_keys_js__rspack_import_1.mK),
|
|
159
|
-
mV: () => (/* reexport safe */ _permissions_js__rspack_import_0.mV),
|
|
160
|
-
rH: () => (/* reexport safe */ _permissions_js__rspack_import_0.rH),
|
|
161
|
-
t$: () => (/* reexport safe */ _permissions_js__rspack_import_0.t$),
|
|
162
|
-
w7: () => (/* reexport safe */ _permissions_js__rspack_import_0.w7),
|
|
163
|
-
wA: () => (/* reexport safe */ _permissions_js__rspack_import_0.wA),
|
|
164
|
-
wM: () => (/* reexport safe */ _permissions_js__rspack_import_0.wM),
|
|
165
|
-
z$: () => (/* reexport safe */ _permissions_js__rspack_import_0.z$),
|
|
166
|
-
zd: () => (/* reexport safe */ _permissions_js__rspack_import_0.zd)
|
|
167
|
-
}, {
|
|
168
|
-
Hq: DEFAULT_EVENT_EXCHANGE,
|
|
169
|
-
Lw: PERMISSION_GUARD_CONFIG,
|
|
170
|
-
N7: PERMISSIONS_KEY,
|
|
171
|
-
PT: DOMAIN_EVENT_HANDLER_KEY,
|
|
172
|
-
Qj: EVENT_BUS_INSTANCE,
|
|
173
|
-
SL: EVENT_BUS_MODULE_OPTIONS,
|
|
174
|
-
fG: PERMISSIONS_CACHE_PREFIX,
|
|
175
|
-
iH: IDEMPOTENCY_KEY_HEADER,
|
|
176
|
-
jA: IS_PUBLIC_KEY,
|
|
177
|
-
kC: REQUEST_ID_HEADER,
|
|
178
|
-
mg: IDEMPOTENCY_CACHE_PREFIX,
|
|
179
|
-
nx: DEFAULT_EVENT_TOPIC,
|
|
180
|
-
xw: CLIENT_TYPE_HEADER,
|
|
181
|
-
zl: CACHE_INSTANCE
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
389(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
187
|
-
// ==================== AUTH (Shared across guards/interceptors) ====================
|
|
188
|
-
// These are duplicated in nestjs-auth but needed here to avoid circular dependencies
|
|
189
|
-
const AUTH_MESSAGES = {
|
|
190
|
-
TOKEN_REQUIRED: 'auth.token.required',
|
|
191
|
-
TOKEN_INVALID: 'auth.token.invalid',
|
|
192
|
-
ENTITY_BELOG_ANOTHER_COMPANY: 'entity.belongs.another.company',
|
|
193
|
-
COMPANY_NO_ACCESS: 'auth.company.no.access'
|
|
194
|
-
};
|
|
195
|
-
// ==================== ERROR (HTTP Exceptions) ====================
|
|
196
|
-
const ERROR_MESSAGES = {
|
|
197
|
-
NOT_FOUND: 'error.not.found',
|
|
198
|
-
VALIDATION: 'error.validation',
|
|
199
|
-
UNAUTHORIZED: 'error.unauthorized',
|
|
200
|
-
FORBIDDEN: 'error.forbidden',
|
|
201
|
-
CONFLICT: 'error.conflict',
|
|
202
|
-
DB_FOREIGN_KEY: 'error.db.foreign.key',
|
|
203
|
-
DB_NOT_NULL: 'error.db.not.null',
|
|
204
|
-
DB_INVALID_INPUT: 'error.db.invalid.input',
|
|
205
|
-
DB_VALUE_TOO_LONG: 'error.db.value.too.long',
|
|
206
|
-
DB_CHECK_CONSTRAINT: 'error.db.check.constraint',
|
|
207
|
-
DB_DEADLOCK: 'error.db.deadlock',
|
|
208
|
-
INTERNAL: 'error.internal',
|
|
209
|
-
SERVICE_UNAVAILABLE: 'error.service.unavailable',
|
|
210
|
-
UNKNOWN: 'error.unknown',
|
|
211
|
-
HTTP: 'error.http',
|
|
212
|
-
GENERIC: 'error.generic',
|
|
213
|
-
PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
|
|
214
|
-
INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
|
|
215
|
-
INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
|
|
216
|
-
NO_PERMISSIONS_FOUND: 'error.no.permissions.found',
|
|
217
|
-
ENDPOINT_DISABLED: 'error.endpoint.disabled'
|
|
218
|
-
};
|
|
219
|
-
// ==================== SYSTEM (Infrastructure) ====================
|
|
220
|
-
const SYSTEM_MESSAGES = {
|
|
221
|
-
REPOSITORY_NOT_AVAILABLE: 'system.repository.not.available',
|
|
222
|
-
DATASOURCE_NOT_AVAILABLE: 'system.datasource.not.available',
|
|
223
|
-
DATABASE_CONFIG_NOT_AVAILABLE: 'system.database.config.not.available',
|
|
224
|
-
SERVICE_NOT_AVAILABLE: 'system.service.not.available',
|
|
225
|
-
CONFIG_REQUIRED: 'system.config.required',
|
|
226
|
-
INTERNAL_ERROR: 'system.internal.error',
|
|
227
|
-
DUPLICATE_REQUEST: 'system.duplicate.request',
|
|
228
|
-
INVALID_TENANT_ID: 'system.invalid.tenant.id',
|
|
229
|
-
TENANT_NOT_FOUND: 'system.tenant.not.found',
|
|
230
|
-
TENANT_HEADER_REQUIRED: 'system.tenant.header.required',
|
|
231
|
-
MISSING_PARAMETER: 'system.missing.parameter',
|
|
232
|
-
SDK_NOT_INSTALLED: 'system.sdk.not.installed',
|
|
233
|
-
PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
|
|
234
|
-
INVALID_FILE_KEY: 'system.invalid.file.key'
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
238
|
-
}, {
|
|
239
|
-
UU: ERROR_MESSAGES,
|
|
240
|
-
hg: SYSTEM_MESSAGES,
|
|
241
|
-
mK: AUTH_MESSAGES
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
},
|
|
246
|
-
975(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
247
|
-
// ==================== AUTH MODULE ====================
|
|
248
|
-
const USER_PERMISSIONS = {
|
|
249
|
-
CREATE: 'user.create',
|
|
250
|
-
READ: 'user.read',
|
|
251
|
-
UPDATE: 'user.update',
|
|
252
|
-
DELETE: 'user.delete',
|
|
253
|
-
LOOKUP: 'user.lookup'
|
|
254
|
-
};
|
|
255
|
-
const COMPANY_PERMISSIONS = {
|
|
256
|
-
CREATE: 'company.create',
|
|
257
|
-
READ: 'company.read',
|
|
258
|
-
UPDATE: 'company.update',
|
|
259
|
-
DELETE: 'company.delete'
|
|
260
|
-
};
|
|
261
|
-
const BRANCH_PERMISSIONS = {
|
|
262
|
-
CREATE: 'branch.create',
|
|
263
|
-
READ: 'branch.read',
|
|
264
|
-
UPDATE: 'branch.update',
|
|
265
|
-
DELETE: 'branch.delete'
|
|
266
|
-
};
|
|
267
|
-
const SOCIAL_AUTH_CONFIG_PERMISSIONS = {
|
|
268
|
-
CREATE: 'social-config.create',
|
|
269
|
-
READ: 'social-config.read',
|
|
270
|
-
UPDATE: 'social-config.update',
|
|
271
|
-
DELETE: 'social-config.delete'
|
|
272
|
-
};
|
|
273
|
-
// ==================== IAM MODULE ====================
|
|
274
|
-
const ACTION_PERMISSIONS = {
|
|
275
|
-
CREATE: 'action.create',
|
|
276
|
-
READ: 'action.read',
|
|
277
|
-
UPDATE: 'action.update',
|
|
278
|
-
DELETE: 'action.delete'
|
|
279
|
-
};
|
|
280
|
-
const ROLE_PERMISSIONS = {
|
|
281
|
-
CREATE: 'role.create',
|
|
282
|
-
READ: 'role.read',
|
|
283
|
-
UPDATE: 'role.update',
|
|
284
|
-
DELETE: 'role.delete'
|
|
285
|
-
};
|
|
286
|
-
const ROLE_ACTION_PERMISSIONS = {
|
|
287
|
-
READ: 'role-action.read',
|
|
288
|
-
ASSIGN: 'role-action.assign'
|
|
289
|
-
};
|
|
290
|
-
const USER_ROLE_PERMISSIONS = {
|
|
291
|
-
READ: 'user-role.read',
|
|
292
|
-
ASSIGN: 'user-role.assign'
|
|
293
|
-
};
|
|
294
|
-
const USER_ACTION_PERMISSIONS = {
|
|
295
|
-
READ: 'user-action.read',
|
|
296
|
-
ASSIGN: 'user-action.assign'
|
|
297
|
-
};
|
|
298
|
-
const COMPANY_ACTION_PERMISSIONS = {
|
|
299
|
-
READ: 'company-action.read',
|
|
300
|
-
ASSIGN: 'company-action.assign'
|
|
301
|
-
};
|
|
302
|
-
// ==================== STORAGE MODULE ====================
|
|
303
|
-
const FILE_PERMISSIONS = {
|
|
304
|
-
CREATE: 'file.create',
|
|
305
|
-
READ: 'file.read',
|
|
306
|
-
UPDATE: 'file.update',
|
|
307
|
-
DELETE: 'file.delete',
|
|
308
|
-
VIEW_PRIVATE_ACTION: 'file.view.private'
|
|
309
|
-
};
|
|
310
|
-
const FOLDER_PERMISSIONS = {
|
|
311
|
-
CREATE: 'folder.create',
|
|
312
|
-
READ: 'folder.read',
|
|
313
|
-
UPDATE: 'folder.update',
|
|
314
|
-
DELETE: 'folder.delete'
|
|
315
|
-
};
|
|
316
|
-
const STORAGE_CONFIG_PERMISSIONS = {
|
|
317
|
-
CREATE: 'storage-config.create',
|
|
318
|
-
READ: 'storage-config.read',
|
|
319
|
-
UPDATE: 'storage-config.update',
|
|
320
|
-
DELETE: 'storage-config.delete'
|
|
321
|
-
};
|
|
322
|
-
const UPLOAD_CONFIG_PERMISSIONS = {
|
|
323
|
-
DELETE: 'upload-config.delete'
|
|
324
|
-
};
|
|
325
|
-
// ==================== EMAIL MODULE ====================
|
|
326
|
-
const EMAIL_CONFIG_PERMISSIONS = {
|
|
327
|
-
CREATE: 'email-config.create',
|
|
328
|
-
READ: 'email-config.read',
|
|
329
|
-
UPDATE: 'email-config.update',
|
|
330
|
-
DELETE: 'email-config.delete'
|
|
331
|
-
};
|
|
332
|
-
const EMAIL_TEMPLATE_PERMISSIONS = {
|
|
333
|
-
CREATE: 'email-template.create',
|
|
334
|
-
READ: 'email-template.read',
|
|
335
|
-
UPDATE: 'email-template.update',
|
|
336
|
-
DELETE: 'email-template.delete'
|
|
337
|
-
};
|
|
338
|
-
// ==================== FORM BUILDER MODULE ====================
|
|
339
|
-
const FORM_PERMISSIONS = {
|
|
340
|
-
CREATE: 'form.create',
|
|
341
|
-
READ: 'form.read',
|
|
342
|
-
UPDATE: 'form.update',
|
|
343
|
-
DELETE: 'form.delete'
|
|
344
|
-
};
|
|
345
|
-
const FORM_RESULT_PERMISSIONS = {
|
|
346
|
-
CREATE: 'form-result.create',
|
|
347
|
-
READ: 'form-result.read',
|
|
348
|
-
UPDATE: 'form-result.update',
|
|
349
|
-
DELETE: 'form-result.delete'
|
|
350
|
-
};
|
|
351
|
-
// ==================== ENTITY BUILDER MODULE ====================
|
|
352
|
-
// Static metadata permissions only. Per-dynamic-entity record permissions
|
|
353
|
-
// (`entity_builder.entity.<entityCode>.<action>`) are checked by flows running as the caller;
|
|
354
|
-
// ENTITY_BUILDER_ALL_DYNAMIC is the wildcard that grants all of them (and nothing else).
|
|
355
|
-
const ENTITY_DEFINITION_PERMISSIONS = {
|
|
356
|
-
CREATE: 'entity_builder.entity_definition.create',
|
|
357
|
-
READ: 'entity_builder.entity_definition.read',
|
|
358
|
-
UPDATE: 'entity_builder.entity_definition.update',
|
|
359
|
-
DELETE: 'entity_builder.entity_definition.delete'
|
|
360
|
-
};
|
|
361
|
-
const FIELD_DEFINITION_PERMISSIONS = {
|
|
362
|
-
READ: 'entity_builder.field_definition.read',
|
|
363
|
-
UPDATE: 'entity_builder.field_definition.update'
|
|
364
|
-
};
|
|
365
|
-
const FLOW_DEFINITION_PERMISSIONS = {
|
|
366
|
-
CREATE: 'entity_builder.flow_definition.create',
|
|
367
|
-
READ: 'entity_builder.flow_definition.read',
|
|
368
|
-
UPDATE: 'entity_builder.flow_definition.update',
|
|
369
|
-
DELETE: 'entity_builder.flow_definition.delete',
|
|
370
|
-
TEST: 'entity_builder.flow_definition.test',
|
|
371
|
-
/** Needed to save a flow containing a code node (sandboxed JavaScript). */ CODE: 'entity_builder.flow_definition.code'
|
|
372
|
-
};
|
|
373
|
-
const ENTITY_BUILDER_DYNAMIC_PREFIX = 'entity_builder.entity';
|
|
374
|
-
const ENTITY_BUILDER_ALL_DYNAMIC = {
|
|
375
|
-
ALL: `${ENTITY_BUILDER_DYNAMIC_PREFIX}.*`
|
|
376
|
-
};
|
|
377
|
-
const dynamicEntityPermissionParent = (entityCode)=>`${ENTITY_BUILDER_DYNAMIC_PREFIX}.${entityCode}`;
|
|
378
|
-
const dynamicEntityPermission = (entityCode, action)=>`${dynamicEntityPermissionParent(entityCode)}.${action}`;
|
|
379
|
-
// ==================== EVENT MANAGER MODULE ====================
|
|
380
|
-
const EVENT_PERMISSIONS = {
|
|
381
|
-
CREATE: 'event.create',
|
|
382
|
-
READ: 'event.read',
|
|
383
|
-
UPDATE: 'event.update',
|
|
384
|
-
DELETE: 'event.delete'
|
|
385
|
-
};
|
|
386
|
-
// ==================== NOTIFICATION MODULE ====================
|
|
387
|
-
const NOTIFICATION_PERMISSIONS = {
|
|
388
|
-
CREATE: 'notification.create',
|
|
389
|
-
READ: 'notification.read',
|
|
390
|
-
UPDATE: 'notification.update',
|
|
391
|
-
DELETE: 'notification.delete'
|
|
392
|
-
};
|
|
393
|
-
// ==================== LOCALIZATION MODULE ====================
|
|
394
|
-
const LANGUAGE_PERMISSIONS = {
|
|
395
|
-
CREATE: 'language.create',
|
|
396
|
-
READ: 'language.read',
|
|
397
|
-
UPDATE: 'language.update',
|
|
398
|
-
DELETE: 'language.delete'
|
|
399
|
-
};
|
|
400
|
-
const TRANSLATION_KEY_PERMISSIONS = {
|
|
401
|
-
CREATE: 'translation-key.create',
|
|
402
|
-
READ: 'translation-key.read',
|
|
403
|
-
UPDATE: 'translation-key.update',
|
|
404
|
-
DELETE: 'translation-key.delete'
|
|
405
|
-
};
|
|
406
|
-
const TRANSLATION_PERMISSIONS = {
|
|
407
|
-
CREATE: 'translation.create',
|
|
408
|
-
READ: 'translation.read',
|
|
409
|
-
UPDATE: 'translation.update',
|
|
410
|
-
DELETE: 'translation.delete'
|
|
411
|
-
};
|
|
412
|
-
// ==================== TASK MANAGER MODULE ====================
|
|
413
|
-
const TASK_BOARD_PERMISSIONS = {
|
|
414
|
-
CREATE: 'task-board.create',
|
|
415
|
-
READ: 'task-board.read',
|
|
416
|
-
UPDATE: 'task-board.update',
|
|
417
|
-
DELETE: 'task-board.delete',
|
|
418
|
-
MANAGE_MEMBERS: 'task-board.manage-members'
|
|
419
|
-
};
|
|
420
|
-
const TASK_LIST_PERMISSIONS = {
|
|
421
|
-
CREATE: 'task-list.create',
|
|
422
|
-
READ: 'task-list.read',
|
|
423
|
-
UPDATE: 'task-list.update',
|
|
424
|
-
DELETE: 'task-list.delete'
|
|
425
|
-
};
|
|
426
|
-
const TASK_PERMISSIONS = {
|
|
427
|
-
CREATE: 'task.create',
|
|
428
|
-
READ: 'task.read',
|
|
429
|
-
UPDATE: 'task.update',
|
|
430
|
-
DELETE: 'task.delete',
|
|
431
|
-
MOVE: 'task.move',
|
|
432
|
-
ASSIGN: 'task.assign'
|
|
433
|
-
};
|
|
434
|
-
const TASK_LABEL_PERMISSIONS = {
|
|
435
|
-
CREATE: 'task-label.create',
|
|
436
|
-
READ: 'task-label.read',
|
|
437
|
-
UPDATE: 'task-label.update',
|
|
438
|
-
DELETE: 'task-label.delete'
|
|
439
|
-
};
|
|
440
|
-
const TASK_COMMENT_PERMISSIONS = {
|
|
441
|
-
CREATE: 'task-comment.create',
|
|
442
|
-
READ: 'task-comment.read',
|
|
443
|
-
DELETE: 'task-comment.delete'
|
|
444
|
-
};
|
|
445
|
-
// ==================== AI ASSISTANT MODULE ====================
|
|
446
|
-
const AI_ASSISTANT_PERMISSIONS = {
|
|
447
|
-
VIEW_ALL_HISTORY: 'ai-assistant.view-all-history'
|
|
448
|
-
};
|
|
449
|
-
// ==================== AGGREGATED EXPORTS ====================
|
|
450
|
-
const PERMISSIONS = {
|
|
451
|
-
// Auth
|
|
452
|
-
USER: USER_PERMISSIONS,
|
|
453
|
-
COMPANY: COMPANY_PERMISSIONS,
|
|
454
|
-
BRANCH: BRANCH_PERMISSIONS,
|
|
455
|
-
SOCIAL_AUTH_CONFIG: SOCIAL_AUTH_CONFIG_PERMISSIONS,
|
|
456
|
-
// IAM
|
|
457
|
-
ACTION: ACTION_PERMISSIONS,
|
|
458
|
-
ROLE: ROLE_PERMISSIONS,
|
|
459
|
-
ROLE_ACTION: ROLE_ACTION_PERMISSIONS,
|
|
460
|
-
USER_ROLE: USER_ROLE_PERMISSIONS,
|
|
461
|
-
USER_ACTION: USER_ACTION_PERMISSIONS,
|
|
462
|
-
COMPANY_ACTION: COMPANY_ACTION_PERMISSIONS,
|
|
463
|
-
// Storage
|
|
464
|
-
FILE: FILE_PERMISSIONS,
|
|
465
|
-
FOLDER: FOLDER_PERMISSIONS,
|
|
466
|
-
STORAGE_CONFIG: STORAGE_CONFIG_PERMISSIONS,
|
|
467
|
-
// Email
|
|
468
|
-
EMAIL_CONFIG: EMAIL_CONFIG_PERMISSIONS,
|
|
469
|
-
EMAIL_TEMPLATE: EMAIL_TEMPLATE_PERMISSIONS,
|
|
470
|
-
// Form Builder
|
|
471
|
-
FORM: FORM_PERMISSIONS,
|
|
472
|
-
FORM_RESULT: FORM_RESULT_PERMISSIONS,
|
|
473
|
-
// Entity Builder
|
|
474
|
-
ENTITY_DEFINITION: ENTITY_DEFINITION_PERMISSIONS,
|
|
475
|
-
FIELD_DEFINITION: FIELD_DEFINITION_PERMISSIONS,
|
|
476
|
-
FLOW_DEFINITION: FLOW_DEFINITION_PERMISSIONS,
|
|
477
|
-
ENTITY_BUILDER_ALL_DYNAMIC: ENTITY_BUILDER_ALL_DYNAMIC,
|
|
478
|
-
// Event Manager
|
|
479
|
-
EVENT: EVENT_PERMISSIONS,
|
|
480
|
-
// Notification
|
|
481
|
-
NOTIFICATION: NOTIFICATION_PERMISSIONS,
|
|
482
|
-
// Localization
|
|
483
|
-
LANGUAGE: LANGUAGE_PERMISSIONS,
|
|
484
|
-
TRANSLATION_KEY: TRANSLATION_KEY_PERMISSIONS,
|
|
485
|
-
TRANSLATION: TRANSLATION_PERMISSIONS,
|
|
486
|
-
// Task Manager
|
|
487
|
-
TASK_BOARD: TASK_BOARD_PERMISSIONS,
|
|
488
|
-
TASK_LIST: TASK_LIST_PERMISSIONS,
|
|
489
|
-
TASK: TASK_PERMISSIONS,
|
|
490
|
-
TASK_LABEL: TASK_LABEL_PERMISSIONS,
|
|
491
|
-
TASK_COMMENT: TASK_COMMENT_PERMISSIONS,
|
|
492
|
-
// AI Assistant
|
|
493
|
-
AI_ASSISTANT: AI_ASSISTANT_PERMISSIONS
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
497
|
-
}, {
|
|
498
|
-
BC: USER_PERMISSIONS,
|
|
499
|
-
Bz: AI_ASSISTANT_PERMISSIONS,
|
|
500
|
-
DP: ENTITY_DEFINITION_PERMISSIONS,
|
|
501
|
-
Em: STORAGE_CONFIG_PERMISSIONS,
|
|
502
|
-
G0: ENTITY_BUILDER_ALL_DYNAMIC,
|
|
503
|
-
GH: dynamicEntityPermissionParent,
|
|
504
|
-
GT: FORM_RESULT_PERMISSIONS,
|
|
505
|
-
Jj: PERMISSIONS,
|
|
506
|
-
N3: TRANSLATION_KEY_PERMISSIONS,
|
|
507
|
-
ON: TASK_LIST_PERMISSIONS,
|
|
508
|
-
P0: ROLE_ACTION_PERMISSIONS,
|
|
509
|
-
Q5: LANGUAGE_PERMISSIONS,
|
|
510
|
-
S6: FILE_PERMISSIONS,
|
|
511
|
-
T: TASK_PERMISSIONS,
|
|
512
|
-
UB: UPLOAD_CONFIG_PERMISSIONS,
|
|
513
|
-
UG: TASK_LABEL_PERMISSIONS,
|
|
514
|
-
Ub: EVENT_PERMISSIONS,
|
|
515
|
-
V0: EMAIL_CONFIG_PERMISSIONS,
|
|
516
|
-
Wc: FORM_PERMISSIONS,
|
|
517
|
-
Y3: TASK_BOARD_PERMISSIONS,
|
|
518
|
-
Y7: ACTION_PERMISSIONS,
|
|
519
|
-
_X: USER_ACTION_PERMISSIONS,
|
|
520
|
-
aO: COMPANY_ACTION_PERMISSIONS,
|
|
521
|
-
aT: dynamicEntityPermission,
|
|
522
|
-
fS: TRANSLATION_PERMISSIONS,
|
|
523
|
-
kA: FIELD_DEFINITION_PERMISSIONS,
|
|
524
|
-
kd: FLOW_DEFINITION_PERMISSIONS,
|
|
525
|
-
l3: SOCIAL_AUTH_CONFIG_PERMISSIONS,
|
|
526
|
-
mV: ROLE_PERMISSIONS,
|
|
527
|
-
rH: NOTIFICATION_PERMISSIONS,
|
|
528
|
-
t$: COMPANY_PERMISSIONS,
|
|
529
|
-
w7: USER_ROLE_PERMISSIONS,
|
|
530
|
-
wA: BRANCH_PERMISSIONS,
|
|
531
|
-
wM: FOLDER_PERMISSIONS,
|
|
532
|
-
z$: EMAIL_TEMPLATE_PERMISSIONS,
|
|
533
|
-
zd: TASK_COMMENT_PERMISSIONS
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
},
|
|
538
|
-
863(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
194
|
+
6863(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
539
195
|
|
|
540
196
|
// EXPORTS
|
|
541
197
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -546,11 +202,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
546
202
|
Ul: () => (/* reexport */ SetDeletedByOnBody),
|
|
547
203
|
_x: () => (/* reexport */ SetUpdateByOnBody),
|
|
548
204
|
Mw: () => (/* reexport */ Slug),
|
|
205
|
+
NM: () => (/* reexport */ buildIdempotencyCacheKey),
|
|
549
206
|
BR: () => (/* reexport */ createSetUserFieldInterceptor)
|
|
550
207
|
});
|
|
551
208
|
|
|
552
209
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
553
|
-
var common_ = __webpack_require__(
|
|
210
|
+
var common_ = __webpack_require__(6157);
|
|
554
211
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/delete-empty-id-from-body.interceptor.ts
|
|
555
212
|
function _ts_decorate(decorators, target, key, desc) {
|
|
556
213
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -569,19 +226,13 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
569
226
|
class DeleteEmptyIdFromBodyInterceptor {
|
|
570
227
|
intercept(context, next) {
|
|
571
228
|
const request = context.switchToHttp().getRequest();
|
|
572
|
-
|
|
573
|
-
request.body
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
});
|
|
579
|
-
} else if (typeof request.body === 'object' && request.body !== null) {
|
|
580
|
-
const item = request.body;
|
|
581
|
-
if (!item?.id || item?.id === '' || item?.id === null) {
|
|
582
|
-
delete item.id;
|
|
229
|
+
const items = Array.isArray(request.body) ? request.body : [
|
|
230
|
+
request.body
|
|
231
|
+
];
|
|
232
|
+
for (const item of items){
|
|
233
|
+
if (typeof item === 'object' && item !== null && !item['id']) {
|
|
234
|
+
delete item['id'];
|
|
583
235
|
}
|
|
584
|
-
request.body = item;
|
|
585
236
|
}
|
|
586
237
|
return next.handle();
|
|
587
238
|
}
|
|
@@ -595,9 +246,11 @@ DeleteEmptyIdFromBodyInterceptor = _ts_decorate([
|
|
|
595
246
|
;// CONCATENATED MODULE: external "rxjs/operators"
|
|
596
247
|
|
|
597
248
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/hybrid-cache.class.ts + 3 modules
|
|
598
|
-
var hybrid_cache_class = __webpack_require__(
|
|
249
|
+
var hybrid_cache_class = __webpack_require__(5375);
|
|
599
250
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
600
|
-
var constants = __webpack_require__(
|
|
251
|
+
var constants = __webpack_require__(6043);
|
|
252
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts + 1 modules
|
|
253
|
+
var logger_middleware = __webpack_require__(8244);
|
|
601
254
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/idempotency.interceptor.ts
|
|
602
255
|
function idempotency_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
603
256
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -627,47 +280,54 @@ function _ts_param(paramIndex, decorator) {
|
|
|
627
280
|
|
|
628
281
|
|
|
629
282
|
|
|
283
|
+
|
|
284
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
285
|
+
/** Bounds how long a crashed instance can hold a key; no request runs this long */ const PROCESSING_TTL_MS = 10 * 60 * 1000;
|
|
286
|
+
/**
|
|
287
|
+
* Replays the stored response for a repeated `X-Idempotency-Key`. A key only ever replays for the
|
|
288
|
+
* same tenant, user and endpoint, and a failed request releases it so the client can retry.
|
|
289
|
+
*/ function buildIdempotencyCacheKey(request, idempotencyKey) {
|
|
290
|
+
const tenant = (0,logger_middleware/* .getTenantId */.EO)() ?? '-';
|
|
291
|
+
const user = request.user?.id ?? 'anonymous';
|
|
292
|
+
const endpoint = `${request.method ?? ''} ${request.route?.path ?? request.originalUrl ?? request.url ?? ''}`;
|
|
293
|
+
return `${constants/* .IDEMPOTENCY_CACHE_PREFIX */.mg}:${tenant}:${user}:${endpoint}:${idempotencyKey}`;
|
|
294
|
+
}
|
|
630
295
|
class IdempotencyInterceptor {
|
|
631
296
|
cache;
|
|
632
|
-
CACHE_TTL = 24 * 60 * 60 * 1000;
|
|
633
|
-
PROCESSING_MARKER = '__PROCESSING__';
|
|
634
297
|
constructor(cache){
|
|
635
298
|
this.cache = cache;
|
|
636
299
|
}
|
|
637
300
|
async intercept(context, next) {
|
|
638
|
-
|
|
639
|
-
if (!
|
|
640
|
-
return next.handle();
|
|
641
|
-
}
|
|
301
|
+
const cache = this.cache;
|
|
302
|
+
if (!cache) return next.handle();
|
|
642
303
|
const request = context.switchToHttp().getRequest();
|
|
643
304
|
const idempotencyKey = request.headers[constants/* .IDEMPOTENCY_KEY_HEADER */.iH];
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
305
|
+
if (!idempotencyKey || typeof idempotencyKey !== 'string') return next.handle();
|
|
306
|
+
const cacheKey = buildIdempotencyCacheKey(request, idempotencyKey);
|
|
307
|
+
const stored = await cache.get(cacheKey, {
|
|
308
|
+
skipMemory: true
|
|
309
|
+
});
|
|
310
|
+
if (stored !== undefined) return (0,__rspack_external_rxjs.of)(stored);
|
|
311
|
+
// Atomic across instances: of two concurrent requests with one key, exactly one runs
|
|
312
|
+
if (!await cache.claim(cacheKey, PROCESSING_TTL_MS)) {
|
|
313
|
+
throw new common_.ConflictException({
|
|
314
|
+
success: false,
|
|
315
|
+
message: 'Request is already being processed',
|
|
316
|
+
messageKey: constants/* .SYSTEM_MESSAGES.DUPLICATE_REQUEST */.hg.DUPLICATE_REQUEST
|
|
317
|
+
});
|
|
647
318
|
}
|
|
648
|
-
const
|
|
649
|
-
//
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
message: 'Request is already being processed',
|
|
657
|
-
messageKey: constants/* .SYSTEM_MESSAGES.DUPLICATE_REQUEST */.hg.DUPLICATE_REQUEST
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
// Return cached response
|
|
661
|
-
return (0,__rspack_external_rxjs.of)(cached);
|
|
319
|
+
const release = ()=>cache.releaseClaim(cacheKey).catch(()=>undefined);
|
|
320
|
+
// The first request may have stored its response and released the claim between our read and claim
|
|
321
|
+
const storedMeanwhile = await cache.get(cacheKey, {
|
|
322
|
+
skipMemory: true
|
|
323
|
+
}).catch(()=>undefined);
|
|
324
|
+
if (storedMeanwhile !== undefined) {
|
|
325
|
+
await release();
|
|
326
|
+
return (0,__rspack_external_rxjs.of)(storedMeanwhile);
|
|
662
327
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
// Process request and cache response
|
|
667
|
-
return next.handle().pipe((0,__rspack_external_rxjs_operators_2eaa0997.tap)(async (response)=>{
|
|
668
|
-
// Cache the successful response
|
|
669
|
-
await cache.set(cacheKey, response, this.CACHE_TTL);
|
|
670
|
-
}));
|
|
328
|
+
return next.handle().pipe((0,__rspack_external_rxjs_operators_2eaa0997.concatMap)((response)=>(0,__rspack_external_rxjs.from)(cache.set(cacheKey, response, CACHE_TTL_MS, {
|
|
329
|
+
skipMemory: true
|
|
330
|
+
}).catch(()=>undefined).then(release).then(()=>response))), (0,__rspack_external_rxjs_operators_2eaa0997.catchError)((error)=>(0,__rspack_external_rxjs.from)(release()).pipe((0,__rspack_external_rxjs_operators_2eaa0997.concatMap)(()=>(0,__rspack_external_rxjs.throwError)(()=>error)))));
|
|
671
331
|
}
|
|
672
332
|
}
|
|
673
333
|
IdempotencyInterceptor = idempotency_interceptor_ts_decorate([
|
|
@@ -681,7 +341,7 @@ IdempotencyInterceptor = idempotency_interceptor_ts_decorate([
|
|
|
681
341
|
], IdempotencyInterceptor);
|
|
682
342
|
|
|
683
343
|
// EXTERNAL MODULE: external "crypto"
|
|
684
|
-
var external_crypto_ = __webpack_require__(
|
|
344
|
+
var external_crypto_ = __webpack_require__(7823);
|
|
685
345
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/response-meta.interceptor.ts
|
|
686
346
|
function response_meta_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
687
347
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -772,7 +432,7 @@ const SetUpdateByOnBody = createSetUserFieldInterceptor('updatedById');
|
|
|
772
432
|
const SetDeletedByOnBody = createSetUserFieldInterceptor('deletedById');
|
|
773
433
|
|
|
774
434
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/modules/utils/utils.service.ts
|
|
775
|
-
var utils_service = __webpack_require__(
|
|
435
|
+
var utils_service = __webpack_require__(1169);
|
|
776
436
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/slug.interceptor.ts
|
|
777
437
|
function slug_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
778
438
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -806,26 +466,18 @@ class Slug {
|
|
|
806
466
|
}
|
|
807
467
|
intercept(context, next) {
|
|
808
468
|
const request = context.switchToHttp().getRequest();
|
|
809
|
-
|
|
810
|
-
request.body = request.body.map((item)=>{
|
|
811
|
-
// Only generate slug if not provided and name exists
|
|
812
|
-
if (!item.slug && item?.name) {
|
|
813
|
-
return {
|
|
814
|
-
...item,
|
|
815
|
-
slug: this.utilsService.transformToSlug(item.name)
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
return item;
|
|
819
|
-
});
|
|
820
|
-
} else if (!request.body?.slug && request.body?.name) {
|
|
821
|
-
// Only generate slug if not provided and name exists
|
|
822
|
-
request.body = {
|
|
823
|
-
...request.body,
|
|
824
|
-
slug: this.utilsService.transformToSlug(request.body.name)
|
|
825
|
-
};
|
|
826
|
-
}
|
|
469
|
+
request.body = Array.isArray(request.body) ? request.body.map((item)=>this.withSlug(item)) : this.withSlug(request.body);
|
|
827
470
|
return next.handle();
|
|
828
471
|
}
|
|
472
|
+
withSlug(item) {
|
|
473
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) return item;
|
|
474
|
+
const body = item;
|
|
475
|
+
if (body['slug'] || typeof body['name'] !== 'string' || !body['name']) return item;
|
|
476
|
+
return {
|
|
477
|
+
...body,
|
|
478
|
+
slug: this.utilsService.transformToSlug(body['name'])
|
|
479
|
+
};
|
|
480
|
+
}
|
|
829
481
|
}
|
|
830
482
|
Slug = slug_interceptor_ts_decorate([
|
|
831
483
|
(0,common_.Injectable)(),
|
|
@@ -845,8 +497,10 @@ Slug = slug_interceptor_ts_decorate([
|
|
|
845
497
|
|
|
846
498
|
|
|
847
499
|
},
|
|
848
|
-
|
|
849
|
-
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(
|
|
500
|
+
1169(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
501
|
+
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
502
|
+
/* import */ var node_crypto__rspack_import_1 = __webpack_require__(2561);
|
|
503
|
+
/* import */ var _utils_string_util_js__rspack_import_2 = __webpack_require__(3366);
|
|
850
504
|
function _ts_decorate(decorators, target, key, desc) {
|
|
851
505
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
852
506
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -861,61 +515,42 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
861
515
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
862
516
|
}
|
|
863
517
|
|
|
518
|
+
|
|
519
|
+
|
|
864
520
|
class UtilsService {
|
|
521
|
+
logger = new _nestjs_common__rspack_import_0.Logger(UtilsService.name);
|
|
865
522
|
// ---------------- CACHE HELPERS ----------------
|
|
866
523
|
/**
|
|
867
|
-
*
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
return `${prefix}entity_${entityName}_all_${JSON.stringify(params)}`;
|
|
524
|
+
* The combined version stamp of every entity a cached read depends on. Read it BEFORE querying
|
|
525
|
+
* the database: a write that commits mid-read moves the stamp, so the stale result is stored
|
|
526
|
+
* under a key no later read asks for.
|
|
527
|
+
*/ async getCacheStamp(cacheManager, entityNames, tenantId) {
|
|
528
|
+
const stamps = await Promise.all(entityNames.map((name)=>cacheManager.getStamp(this.getStampName(name, tenantId))));
|
|
529
|
+
return stamps.join('.');
|
|
874
530
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
const trackingKey = this.buildTrackingKey(entityName, entityId, tenantId);
|
|
880
|
-
const keys = await cacheManager.get(trackingKey) || [];
|
|
881
|
-
if (!keys.includes(cacheKey)) keys.push(cacheKey);
|
|
882
|
-
await cacheManager.set(trackingKey, keys);
|
|
883
|
-
} catch {
|
|
884
|
-
// Silent failure - cache tracking is non-critical
|
|
885
|
-
}
|
|
531
|
+
getCacheKey(entityName, params, entityId, tenantId, stamp) {
|
|
532
|
+
const scope = entityId ? `id_${entityId}` : 'all';
|
|
533
|
+
const digest = (0,node_crypto__rspack_import_1.createHash)('sha256').update(JSON.stringify(params ?? null)).digest('hex');
|
|
534
|
+
return `${this.buildTenantPrefix(tenantId)}entity_${entityName}_${scope}_${stamp}_${digest}`;
|
|
886
535
|
}
|
|
887
|
-
/**
|
|
888
|
-
* Clear cache for entity with optional tenant prefix
|
|
889
|
-
*/ async clearCache(entityName, cacheManager, entityId, tenantId) {
|
|
536
|
+
/** Invalidates every cached list and row of `entityName` in the tenant, on every instance */ async clearCache(entityName, cacheManager, tenantId) {
|
|
890
537
|
try {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
await cacheManager.del(trackingKey);
|
|
895
|
-
} catch {
|
|
896
|
-
// Silent failure - cache invalidation is non-critical
|
|
538
|
+
await cacheManager.bumpStamp(this.getStampName(entityName, tenantId));
|
|
539
|
+
} catch (error) {
|
|
540
|
+
this.logger.error(`Cache invalidation failed for '${entityName}': ${error.message}`);
|
|
897
541
|
}
|
|
898
542
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
* Transform string to URL-friendly slug
|
|
902
|
-
*/ transformToSlug(value, salt) {
|
|
903
|
-
const slug = value?.trim().replace(/[^A-Z0-9]+/gi, '-').toLowerCase();
|
|
904
|
-
return salt ? `${slug}-${this.getRandomInt(1, 100)}` : slug;
|
|
543
|
+
/** The stamp `clearCache` bumps; for callers that must see the bump fail instead of having it logged */ getStampName(entityName, tenantId) {
|
|
544
|
+
return `${this.buildTenantPrefix(tenantId)}entity_${entityName}`;
|
|
905
545
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
546
|
+
// ---------------- STRING HELPERS ----------------
|
|
547
|
+
transformToSlug(value) {
|
|
548
|
+
return (0,_utils_string_util_js__rspack_import_2/* .generateSlug */.z)(value);
|
|
910
549
|
}
|
|
911
550
|
// ---------------- PRIVATE HELPERS ----------------
|
|
912
551
|
buildTenantPrefix(tenantId) {
|
|
913
552
|
return tenantId ? `tenant_${tenantId}_` : '';
|
|
914
553
|
}
|
|
915
|
-
buildTrackingKey(entityName, entityId, tenantId) {
|
|
916
|
-
const prefix = this.buildTenantPrefix(tenantId);
|
|
917
|
-
return entityId ? `${prefix}entity_${entityName}_id_${entityId}_keys` : `${prefix}entity_${entityName}_keys`;
|
|
918
|
-
}
|
|
919
554
|
}
|
|
920
555
|
UtilsService = _ts_decorate([
|
|
921
556
|
(0,_nestjs_common__rspack_import_0.Injectable)()
|
|
@@ -927,19 +562,81 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
927
562
|
|
|
928
563
|
|
|
929
564
|
},
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
565
|
+
3366(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
566
|
+
/**
|
|
567
|
+
* URL-friendly slug: lower case, words joined by single hyphens. Latin accents are folded
|
|
568
|
+
* (`Café` -> `cafe`) and letters of other scripts are kept, so a non-Latin name never
|
|
569
|
+
* collapses to an empty slug. Never starts or ends with a hyphen, also after truncation.
|
|
570
|
+
*
|
|
571
|
+
* @example
|
|
572
|
+
* generateSlug('My Company Name') // 'my-company-name'
|
|
573
|
+
* generateSlug('Hello World!') // 'hello-world'
|
|
574
|
+
*/ function generateSlug(text, maxLength = 100) {
|
|
575
|
+
const slug = text.normalize('NFKD').toLowerCase().replace(/([a-z0-9])\p{M}+/gu, '$1').replace(/[^\p{L}\p{N}\p{M}\s-]/gu, '').trim().replace(/[\s-]+/g, '-').replace(/^-+|-+$/g, '').normalize('NFC');
|
|
576
|
+
return Array.from(slug).slice(0, Math.max(maxLength, 0)).join('').replace(/-+$/, '');
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Generate unique slug using single database query (optimized for large datasets)
|
|
580
|
+
* Appends numeric suffix if collision exists (e.g., 'my-company-1', 'my-company-2')
|
|
581
|
+
*
|
|
582
|
+
* Performance: O(1) database query regardless of collision count
|
|
583
|
+
* - Works efficiently with millions of records
|
|
584
|
+
* - Requires index on slug column for best performance
|
|
585
|
+
*
|
|
586
|
+
* @param text - The text to convert to slug
|
|
587
|
+
* @param findMatchingSlugs - Async function that returns all slugs matching base pattern
|
|
588
|
+
* Should query: WHERE slug = baseSlug OR slug LIKE 'baseSlug-%'
|
|
589
|
+
* @param maxLength - Maximum length of the base slug (default: 100)
|
|
590
|
+
* @returns Unique URL-friendly slug
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* const slug = await generateUniqueSlug('My Company', async (baseSlug) => {
|
|
594
|
+
* return repo
|
|
595
|
+
* .createQueryBuilder('c')
|
|
596
|
+
* .select('c.slug')
|
|
597
|
+
* .where('c.slug = :base OR c.slug LIKE :pattern', {
|
|
598
|
+
* base: baseSlug,
|
|
599
|
+
* pattern: `${baseSlug}-%`,
|
|
600
|
+
* })
|
|
601
|
+
* .getMany()
|
|
602
|
+
* .then(rows => rows.map(r => r.slug));
|
|
603
|
+
* });
|
|
604
|
+
*/ async function generateUniqueSlug(text, findMatchingSlugs, maxLength = 100) {
|
|
605
|
+
const baseSlug = generateSlug(text, maxLength);
|
|
606
|
+
// Single query to get all matching slugs
|
|
607
|
+
const existingSlugs = await findMatchingSlugs(baseSlug);
|
|
608
|
+
// No collisions - base slug is available
|
|
609
|
+
if (existingSlugs.length === 0) {
|
|
610
|
+
return baseSlug;
|
|
611
|
+
}
|
|
612
|
+
// Build set for O(1) lookup
|
|
613
|
+
const existingSet = new Set(existingSlugs);
|
|
614
|
+
// Base slug not taken (only suffixed versions exist)
|
|
615
|
+
if (!existingSet.has(baseSlug)) {
|
|
616
|
+
return baseSlug;
|
|
617
|
+
}
|
|
618
|
+
// Find next available suffix in memory (fast)
|
|
619
|
+
let counter = 1;
|
|
620
|
+
while(counter < 10000){
|
|
621
|
+
const slugWithSuffix = `${baseSlug}-${counter}`;
|
|
622
|
+
if (!existingSet.has(slugWithSuffix)) {
|
|
623
|
+
return slugWithSuffix;
|
|
624
|
+
}
|
|
625
|
+
counter++;
|
|
626
|
+
}
|
|
627
|
+
// Fallback: append random string (extremely rare edge case)
|
|
628
|
+
const randomSuffix = Math.random().toString(36).substring(2, 8);
|
|
629
|
+
return `${baseSlug}-${randomSuffix}`;
|
|
630
|
+
}
|
|
937
631
|
|
|
938
|
-
|
|
632
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
633
|
+
o: () => (generateUniqueSlug),
|
|
634
|
+
z: () => (generateSlug)
|
|
635
|
+
});
|
|
939
636
|
|
|
940
637
|
|
|
941
638
|
},
|
|
942
|
-
|
|
639
|
+
7823(module) {
|
|
943
640
|
|
|
944
641
|
module.exports = __rspack_external_crypto;
|
|
945
642
|
|
|
@@ -949,14 +646,17 @@ module.exports = __rspack_external_crypto;
|
|
|
949
646
|
};
|
|
950
647
|
import { __webpack_require__ } from '../runtime.js';
|
|
951
648
|
var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
|
|
952
|
-
import * as __rspack_chunk_1 from '
|
|
649
|
+
import * as __rspack_chunk_1 from '../997.js';
|
|
953
650
|
__webpack_require__.C(__rspack_chunk_1);
|
|
954
|
-
|
|
651
|
+
import * as __rspack_chunk_2 from './index.js';
|
|
652
|
+
__webpack_require__.C(__rspack_chunk_2);
|
|
653
|
+
var __webpack_exports__ = __webpack_exec__(6863);var __webpack_exports__DeleteEmptyIdFromBodyInterceptor = __webpack_exports__.nd;
|
|
955
654
|
var __webpack_exports__IdempotencyInterceptor = __webpack_exports__.Bw;
|
|
956
655
|
var __webpack_exports__ResponseMetaInterceptor = __webpack_exports__.c_;
|
|
957
656
|
var __webpack_exports__SetCreatedByOnBody = __webpack_exports__.VS;
|
|
958
657
|
var __webpack_exports__SetDeletedByOnBody = __webpack_exports__.Ul;
|
|
959
658
|
var __webpack_exports__SetUpdateByOnBody = __webpack_exports__._x;
|
|
960
659
|
var __webpack_exports__Slug = __webpack_exports__.Mw;
|
|
660
|
+
var __webpack_exports__buildIdempotencyCacheKey = __webpack_exports__.NM;
|
|
961
661
|
var __webpack_exports__createSetUserFieldInterceptor = __webpack_exports__.BR;
|
|
962
|
-
export { __webpack_exports__DeleteEmptyIdFromBodyInterceptor as DeleteEmptyIdFromBodyInterceptor, __webpack_exports__IdempotencyInterceptor as IdempotencyInterceptor, __webpack_exports__ResponseMetaInterceptor as ResponseMetaInterceptor, __webpack_exports__SetCreatedByOnBody as SetCreatedByOnBody, __webpack_exports__SetDeletedByOnBody as SetDeletedByOnBody, __webpack_exports__SetUpdateByOnBody as SetUpdateByOnBody, __webpack_exports__Slug as Slug, __webpack_exports__createSetUserFieldInterceptor as createSetUserFieldInterceptor };
|
|
662
|
+
export { __webpack_exports__DeleteEmptyIdFromBodyInterceptor as DeleteEmptyIdFromBodyInterceptor, __webpack_exports__IdempotencyInterceptor as IdempotencyInterceptor, __webpack_exports__ResponseMetaInterceptor as ResponseMetaInterceptor, __webpack_exports__SetCreatedByOnBody as SetCreatedByOnBody, __webpack_exports__SetDeletedByOnBody as SetDeletedByOnBody, __webpack_exports__SetUpdateByOnBody as SetUpdateByOnBody, __webpack_exports__Slug as Slug, __webpack_exports__buildIdempotencyCacheKey as buildIdempotencyCacheKey, __webpack_exports__createSetUserFieldInterceptor as createSetUserFieldInterceptor };
|