@flusys/nestjs-shared 8.1.5 → 9.1.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 +48 -2
- package/classes/api-service.class.d.ts +3 -0
- package/constants/permissions.d.ts +46 -0
- package/exceptions/base-app.exception.d.ts +3 -2
- package/fesm/{509.js → 183.js} +43 -37
- package/fesm/470.js +228 -105
- package/fesm/667.js +28 -10
- package/fesm/{67.js → 681.js} +97 -19
- package/fesm/{720.js → 948.js} +60 -7
- package/fesm/chunks/123.js +9 -10
- package/fesm/chunks/37.js +7 -8
- package/fesm/classes/index.js +10 -4
- package/fesm/constants/index.js +53 -1
- package/fesm/decorators/index.js +4 -4
- package/fesm/dtos/index.js +2 -2
- package/fesm/guards/index.js +48 -426
- package/fesm/index.js +422 -341
- package/fesm/interceptors/index.js +62 -23
- package/fesm/interfaces/index.js +16 -3
- package/fesm/middlewares/index.js +5 -3
- package/fesm/modules/index.js +6 -414
- package/fesm/pipes/index.js +196 -0
- package/fesm/utils/index.js +125 -10
- package/index.d.ts +1 -0
- package/interfaces/datasource.interface.d.ts +2 -0
- package/interfaces/index.d.ts +3 -0
- package/interfaces/message-ref.interface.d.ts +4 -0
- package/interfaces/permission-action-registry.interface.d.ts +12 -0
- package/interfaces/permission-resolver.interface.d.ts +9 -0
- package/middlewares/logger.middleware.d.ts +4 -0
- package/modules/shared-permission-cache/shared-permission-cache.service.d.ts +5 -0
- package/package.json +8 -2
- package/pipes/dto-body-validation.pipe.d.ts +18 -0
- package/pipes/index.d.ts +1 -0
- package/utils/cache-tenant.util.d.ts +2 -0
- package/utils/index.d.ts +3 -0
- package/utils/message-ref.util.d.ts +2 -0
- package/utils/permission-match.util.d.ts +1 -0
- package/utils/query-helpers.util.d.ts +2 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
|
|
2
|
+
import * as __rspack_external_class_validator_7b99ef4d from "class-validator";
|
|
3
|
+
export const __rspack_esm_id = 360;
|
|
4
|
+
export const __rspack_esm_ids = [360];
|
|
5
|
+
export const __webpack_modules__ = {
|
|
6
|
+
389(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
7
|
+
// ==================== AUTH (Shared across guards/interceptors) ====================
|
|
8
|
+
// These are duplicated in nestjs-auth but needed here to avoid circular dependencies
|
|
9
|
+
const AUTH_MESSAGES = {
|
|
10
|
+
TOKEN_REQUIRED: 'auth.token.required',
|
|
11
|
+
TOKEN_INVALID: 'auth.token.invalid',
|
|
12
|
+
ENTITY_BELOG_ANOTHER_COMPANY: 'entity.belongs.another.company',
|
|
13
|
+
COMPANY_NO_ACCESS: 'auth.company.no.access'
|
|
14
|
+
};
|
|
15
|
+
// ==================== ERROR (HTTP Exceptions) ====================
|
|
16
|
+
const ERROR_MESSAGES = {
|
|
17
|
+
NOT_FOUND: 'error.not.found',
|
|
18
|
+
VALIDATION: 'error.validation',
|
|
19
|
+
UNAUTHORIZED: 'error.unauthorized',
|
|
20
|
+
FORBIDDEN: 'error.forbidden',
|
|
21
|
+
CONFLICT: 'error.conflict',
|
|
22
|
+
DB_FOREIGN_KEY: 'error.db.foreign.key',
|
|
23
|
+
DB_NOT_NULL: 'error.db.not.null',
|
|
24
|
+
DB_INVALID_INPUT: 'error.db.invalid.input',
|
|
25
|
+
DB_VALUE_TOO_LONG: 'error.db.value.too.long',
|
|
26
|
+
DB_CHECK_CONSTRAINT: 'error.db.check.constraint',
|
|
27
|
+
DB_DEADLOCK: 'error.db.deadlock',
|
|
28
|
+
INTERNAL: 'error.internal',
|
|
29
|
+
SERVICE_UNAVAILABLE: 'error.service.unavailable',
|
|
30
|
+
UNKNOWN: 'error.unknown',
|
|
31
|
+
HTTP: 'error.http',
|
|
32
|
+
GENERIC: 'error.generic',
|
|
33
|
+
PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
|
|
34
|
+
INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
|
|
35
|
+
INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
|
|
36
|
+
NO_PERMISSIONS_FOUND: 'error.no.permissions.found',
|
|
37
|
+
ENDPOINT_DISABLED: 'error.endpoint.disabled'
|
|
38
|
+
};
|
|
39
|
+
// ==================== SYSTEM (Infrastructure) ====================
|
|
40
|
+
const SYSTEM_MESSAGES = {
|
|
41
|
+
REPOSITORY_NOT_AVAILABLE: 'system.repository.not.available',
|
|
42
|
+
DATASOURCE_NOT_AVAILABLE: 'system.datasource.not.available',
|
|
43
|
+
DATABASE_CONFIG_NOT_AVAILABLE: 'system.database.config.not.available',
|
|
44
|
+
SERVICE_NOT_AVAILABLE: 'system.service.not.available',
|
|
45
|
+
CONFIG_REQUIRED: 'system.config.required',
|
|
46
|
+
INTERNAL_ERROR: 'system.internal.error',
|
|
47
|
+
DUPLICATE_REQUEST: 'system.duplicate.request',
|
|
48
|
+
INVALID_TENANT_ID: 'system.invalid.tenant.id',
|
|
49
|
+
TENANT_NOT_FOUND: 'system.tenant.not.found',
|
|
50
|
+
TENANT_HEADER_REQUIRED: 'system.tenant.header.required',
|
|
51
|
+
MISSING_PARAMETER: 'system.missing.parameter',
|
|
52
|
+
SDK_NOT_INSTALLED: 'system.sdk.not.installed',
|
|
53
|
+
PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
|
|
54
|
+
INVALID_FILE_KEY: 'system.invalid.file.key'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
58
|
+
}, {
|
|
59
|
+
UU: ERROR_MESSAGES,
|
|
60
|
+
hg: SYSTEM_MESSAGES,
|
|
61
|
+
mK: AUTH_MESSAGES
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
},
|
|
66
|
+
928(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
67
|
+
|
|
68
|
+
// EXPORTS
|
|
69
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
70
|
+
gG: () => (/* reexport */ AUDIT_BODY_KEYS),
|
|
71
|
+
d0: () => (/* reexport */ DEFAULT_VALIDATION_OPTIONS),
|
|
72
|
+
zT: () => (/* reexport */ DtoBodyValidationPipe)
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// EXTERNAL MODULE: external "@nestjs/common"
|
|
76
|
+
var common_ = __webpack_require__(157);
|
|
77
|
+
// EXTERNAL MODULE: external "class-validator"
|
|
78
|
+
var external_class_validator_ = __webpack_require__(421);
|
|
79
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/message-keys.ts
|
|
80
|
+
var message_keys = __webpack_require__(389);
|
|
81
|
+
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/pipes/dto-body-validation.pipe.ts
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
const DEFAULT_VALIDATION_OPTIONS = {
|
|
86
|
+
transform: true,
|
|
87
|
+
whitelist: true,
|
|
88
|
+
forbidNonWhitelisted: true,
|
|
89
|
+
transformOptions: {
|
|
90
|
+
enableImplicitConversion: false
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const AUDIT_BODY_KEYS = [
|
|
94
|
+
'createdById',
|
|
95
|
+
'updatedById',
|
|
96
|
+
'deletedById'
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Validates a generic controller body against its concrete DTO class: a generic
|
|
100
|
+
* `@Body() dto: T` reflects as `Object`, so the global ValidationPipe skips it.
|
|
101
|
+
* Audit keys are never taken from the client: `stampedKeys` (written by the endpoint's
|
|
102
|
+
* SetCreatedByOnBody / SetUpdateByOnBody interceptors, which run first) are kept, any other
|
|
103
|
+
* audit key is dropped. A `slug` the DTO does not declare is the Slug interceptor's and is kept.
|
|
104
|
+
*/ class DtoBodyValidationPipe {
|
|
105
|
+
resolveDto;
|
|
106
|
+
stampedKeys;
|
|
107
|
+
isArray;
|
|
108
|
+
options;
|
|
109
|
+
pipes = new Map();
|
|
110
|
+
constructor(resolveDto, stampedKeys, isArray = false, options = DEFAULT_VALIDATION_OPTIONS){
|
|
111
|
+
this.resolveDto = resolveDto;
|
|
112
|
+
this.stampedKeys = stampedKeys;
|
|
113
|
+
this.isArray = isArray;
|
|
114
|
+
this.options = options;
|
|
115
|
+
}
|
|
116
|
+
static for(dto, stampedKeys, isArray = false) {
|
|
117
|
+
return new DtoBodyValidationPipe(()=>dto, stampedKeys, isArray);
|
|
118
|
+
}
|
|
119
|
+
async transform(value, metadata) {
|
|
120
|
+
if (!this.isArray) return this.validateItem(value, metadata);
|
|
121
|
+
if (!Array.isArray(value)) throw new common_.BadRequestException({
|
|
122
|
+
message: 'Request body must be an array',
|
|
123
|
+
messageKey: message_keys/* .ERROR_MESSAGES.VALIDATION */.UU.VALIDATION
|
|
124
|
+
});
|
|
125
|
+
return Promise.all(value.map((item)=>this.validateItem(item, metadata)));
|
|
126
|
+
}
|
|
127
|
+
async validateItem(item, metadata) {
|
|
128
|
+
if (item === null || typeof item !== 'object' || Array.isArray(item)) {
|
|
129
|
+
throw new common_.BadRequestException({
|
|
130
|
+
message: 'Request body item must be an object',
|
|
131
|
+
messageKey: message_keys/* .ERROR_MESSAGES.VALIDATION */.UU.VALIDATION
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const dto = this.resolveDto(item);
|
|
135
|
+
const rest = {
|
|
136
|
+
...item
|
|
137
|
+
};
|
|
138
|
+
const injected = {};
|
|
139
|
+
for (const key of AUDIT_BODY_KEYS){
|
|
140
|
+
if (!(key in rest)) continue;
|
|
141
|
+
if (this.stampedKeys.includes(key)) injected[key] = rest[key];
|
|
142
|
+
delete rest[key];
|
|
143
|
+
}
|
|
144
|
+
if ('slug' in rest && !declaresProperty(dto, 'slug')) {
|
|
145
|
+
injected['slug'] = rest['slug'];
|
|
146
|
+
delete rest['slug'];
|
|
147
|
+
}
|
|
148
|
+
const validated = await this.pipeFor(dto).transform(rest, {
|
|
149
|
+
...metadata,
|
|
150
|
+
metatype: dto
|
|
151
|
+
});
|
|
152
|
+
return Object.assign(validated, injected);
|
|
153
|
+
}
|
|
154
|
+
pipeFor(dto) {
|
|
155
|
+
let pipe = this.pipes.get(dto);
|
|
156
|
+
if (!pipe) {
|
|
157
|
+
pipe = new common_.ValidationPipe({
|
|
158
|
+
...this.options,
|
|
159
|
+
expectedType: dto
|
|
160
|
+
});
|
|
161
|
+
this.pipes.set(dto, pipe);
|
|
162
|
+
}
|
|
163
|
+
return pipe;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function declaresProperty(dto, key) {
|
|
167
|
+
return (0,external_class_validator_.getMetadataStorage)().getTargetValidationMetadatas(dto, '', true, false).some((m)=>m.propertyName === key);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/pipes/index.ts
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
},
|
|
175
|
+
157(module) {
|
|
176
|
+
|
|
177
|
+
module.exports = __rspack_external__nestjs_common_a04939da;
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
},
|
|
181
|
+
421(module) {
|
|
182
|
+
|
|
183
|
+
module.exports = __rspack_external_class_validator_7b99ef4d;
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
};
|
|
189
|
+
import { __webpack_require__ } from '../runtime.js';
|
|
190
|
+
var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
|
|
191
|
+
import * as __rspack_chunk_1 from './index.js';
|
|
192
|
+
__webpack_require__.C(__rspack_chunk_1);
|
|
193
|
+
var __webpack_exports__ = __webpack_exec__(928);var __webpack_exports__AUDIT_BODY_KEYS = __webpack_exports__.gG;
|
|
194
|
+
var __webpack_exports__DEFAULT_VALIDATION_OPTIONS = __webpack_exports__.d0;
|
|
195
|
+
var __webpack_exports__DtoBodyValidationPipe = __webpack_exports__.zT;
|
|
196
|
+
export { __webpack_exports__AUDIT_BODY_KEYS as AUDIT_BODY_KEYS, __webpack_exports__DEFAULT_VALIDATION_OPTIONS as DEFAULT_VALIDATION_OPTIONS, __webpack_exports__DtoBodyValidationPipe as DtoBodyValidationPipe };
|
package/fesm/utils/index.js
CHANGED
|
@@ -35,7 +35,10 @@ const DEFAULT_EVENT_SERVICE_NAME = 'flusys';
|
|
|
35
35
|
__webpack_require__.d(__webpack_exports__, {
|
|
36
36
|
BC: () => (/* reexport safe */ _permissions_js__rspack_import_0.BC),
|
|
37
37
|
Bz: () => (/* reexport safe */ _permissions_js__rspack_import_0.Bz),
|
|
38
|
+
DP: () => (/* reexport safe */ _permissions_js__rspack_import_0.DP),
|
|
38
39
|
Em: () => (/* reexport safe */ _permissions_js__rspack_import_0.Em),
|
|
40
|
+
G0: () => (/* reexport safe */ _permissions_js__rspack_import_0.G0),
|
|
41
|
+
GH: () => (/* reexport safe */ _permissions_js__rspack_import_0.GH),
|
|
39
42
|
GT: () => (/* reexport safe */ _permissions_js__rspack_import_0.GT),
|
|
40
43
|
Jj: () => (/* reexport safe */ _permissions_js__rspack_import_0.Jj),
|
|
41
44
|
N3: () => (/* reexport safe */ _permissions_js__rspack_import_0.N3),
|
|
@@ -54,8 +57,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
54
57
|
Y7: () => (/* reexport safe */ _permissions_js__rspack_import_0.Y7),
|
|
55
58
|
_X: () => (/* reexport safe */ _permissions_js__rspack_import_0._X),
|
|
56
59
|
aO: () => (/* reexport safe */ _permissions_js__rspack_import_0.aO),
|
|
60
|
+
aT: () => (/* reexport safe */ _permissions_js__rspack_import_0.aT),
|
|
57
61
|
fS: () => (/* reexport safe */ _permissions_js__rspack_import_0.fS),
|
|
58
62
|
hg: () => (/* reexport safe */ _message_keys_js__rspack_import_1.hg),
|
|
63
|
+
kA: () => (/* reexport safe */ _permissions_js__rspack_import_0.kA),
|
|
64
|
+
kd: () => (/* reexport safe */ _permissions_js__rspack_import_0.kd),
|
|
59
65
|
l3: () => (/* reexport safe */ _permissions_js__rspack_import_0.l3),
|
|
60
66
|
mK: () => (/* reexport safe */ _message_keys_js__rspack_import_1.mK),
|
|
61
67
|
mV: () => (/* reexport safe */ _permissions_js__rspack_import_0.mV),
|
|
@@ -250,6 +256,35 @@ const FORM_RESULT_PERMISSIONS = {
|
|
|
250
256
|
UPDATE: 'form-result.update',
|
|
251
257
|
DELETE: 'form-result.delete'
|
|
252
258
|
};
|
|
259
|
+
// ==================== ENTITY BUILDER MODULE ====================
|
|
260
|
+
// Static metadata permissions only. Per-dynamic-entity record permissions
|
|
261
|
+
// (`entity_builder.entity.<entityCode>.<action>`) are checked by flows running as the caller;
|
|
262
|
+
// ENTITY_BUILDER_ALL_DYNAMIC is the wildcard that grants all of them (and nothing else).
|
|
263
|
+
const ENTITY_DEFINITION_PERMISSIONS = {
|
|
264
|
+
CREATE: 'entity_builder.entity_definition.create',
|
|
265
|
+
READ: 'entity_builder.entity_definition.read',
|
|
266
|
+
UPDATE: 'entity_builder.entity_definition.update',
|
|
267
|
+
DELETE: 'entity_builder.entity_definition.delete'
|
|
268
|
+
};
|
|
269
|
+
const FIELD_DEFINITION_PERMISSIONS = {
|
|
270
|
+
READ: 'entity_builder.field_definition.read',
|
|
271
|
+
UPDATE: 'entity_builder.field_definition.update'
|
|
272
|
+
};
|
|
273
|
+
const FLOW_DEFINITION_PERMISSIONS = {
|
|
274
|
+
CREATE: 'entity_builder.flow_definition.create',
|
|
275
|
+
READ: 'entity_builder.flow_definition.read',
|
|
276
|
+
UPDATE: 'entity_builder.flow_definition.update',
|
|
277
|
+
DELETE: 'entity_builder.flow_definition.delete',
|
|
278
|
+
TEST: 'entity_builder.flow_definition.test',
|
|
279
|
+
/** Needed to save a flow that runs as the system (bypassing per-entity permissions). */ SYSTEM: 'entity_builder.flow_definition.system',
|
|
280
|
+
/** Needed to save a flow containing a code node (sandboxed JavaScript). */ CODE: 'entity_builder.flow_definition.code'
|
|
281
|
+
};
|
|
282
|
+
const ENTITY_BUILDER_DYNAMIC_PREFIX = 'entity_builder.entity';
|
|
283
|
+
const ENTITY_BUILDER_ALL_DYNAMIC = {
|
|
284
|
+
ALL: `${ENTITY_BUILDER_DYNAMIC_PREFIX}.*`
|
|
285
|
+
};
|
|
286
|
+
const dynamicEntityPermissionParent = (entityCode)=>`${ENTITY_BUILDER_DYNAMIC_PREFIX}.${entityCode}`;
|
|
287
|
+
const dynamicEntityPermission = (entityCode, action)=>`${dynamicEntityPermissionParent(entityCode)}.${action}`;
|
|
253
288
|
// ==================== EVENT MANAGER MODULE ====================
|
|
254
289
|
const EVENT_PERMISSIONS = {
|
|
255
290
|
CREATE: 'event.create',
|
|
@@ -344,6 +379,11 @@ const PERMISSIONS = {
|
|
|
344
379
|
// Form Builder
|
|
345
380
|
FORM: FORM_PERMISSIONS,
|
|
346
381
|
FORM_RESULT: FORM_RESULT_PERMISSIONS,
|
|
382
|
+
// Entity Builder
|
|
383
|
+
ENTITY_DEFINITION: ENTITY_DEFINITION_PERMISSIONS,
|
|
384
|
+
FIELD_DEFINITION: FIELD_DEFINITION_PERMISSIONS,
|
|
385
|
+
FLOW_DEFINITION: FLOW_DEFINITION_PERMISSIONS,
|
|
386
|
+
ENTITY_BUILDER_ALL_DYNAMIC: ENTITY_BUILDER_ALL_DYNAMIC,
|
|
347
387
|
// Event Manager
|
|
348
388
|
EVENT: EVENT_PERMISSIONS,
|
|
349
389
|
// Notification
|
|
@@ -366,7 +406,10 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
366
406
|
}, {
|
|
367
407
|
BC: USER_PERMISSIONS,
|
|
368
408
|
Bz: AI_ASSISTANT_PERMISSIONS,
|
|
409
|
+
DP: ENTITY_DEFINITION_PERMISSIONS,
|
|
369
410
|
Em: STORAGE_CONFIG_PERMISSIONS,
|
|
411
|
+
G0: ENTITY_BUILDER_ALL_DYNAMIC,
|
|
412
|
+
GH: dynamicEntityPermissionParent,
|
|
370
413
|
GT: FORM_RESULT_PERMISSIONS,
|
|
371
414
|
Jj: PERMISSIONS,
|
|
372
415
|
N3: TRANSLATION_KEY_PERMISSIONS,
|
|
@@ -384,7 +427,10 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
384
427
|
Y7: ACTION_PERMISSIONS,
|
|
385
428
|
_X: USER_ACTION_PERMISSIONS,
|
|
386
429
|
aO: COMPANY_ACTION_PERMISSIONS,
|
|
430
|
+
aT: dynamicEntityPermission,
|
|
387
431
|
fS: TRANSLATION_PERMISSIONS,
|
|
432
|
+
kA: FIELD_DEFINITION_PERMISSIONS,
|
|
433
|
+
kd: FLOW_DEFINITION_PERMISSIONS,
|
|
388
434
|
l3: SOCIAL_AUTH_CONFIG_PERMISSIONS,
|
|
389
435
|
mV: ROLE_PERMISSIONS,
|
|
390
436
|
rH: NOTIFICATION_PERMISSIONS,
|
|
@@ -397,6 +443,21 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
397
443
|
});
|
|
398
444
|
|
|
399
445
|
|
|
446
|
+
},
|
|
447
|
+
154(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
448
|
+
/**
|
|
449
|
+
* The tenant a cache key belongs to: the provider's current tenant in multi-tenant mode, else
|
|
450
|
+
* undefined. A single database never prefixes, so a stray tenant header cannot split its cache.
|
|
451
|
+
*/ function cacheTenantId(provider) {
|
|
452
|
+
if (!provider?.isMultiTenant?.()) return undefined;
|
|
453
|
+
return provider.getCurrentTenantId?.() ?? undefined;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
457
|
+
q: () => (cacheTenantId)
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
|
|
400
461
|
},
|
|
401
462
|
456(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
402
463
|
const SENSITIVE_KEYS = [
|
|
@@ -499,7 +560,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
499
560
|
|
|
500
561
|
|
|
501
562
|
},
|
|
502
|
-
|
|
563
|
+
528(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
503
564
|
|
|
504
565
|
// EXPORTS
|
|
505
566
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -510,6 +571,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
510
571
|
fJ: () => (/* reexport */ buildCookieOptions),
|
|
511
572
|
oV: () => (/* reexport */ buildFrontendUrl),
|
|
512
573
|
nt: () => (/* reexport */ permission_cache_key_util/* .buildPermissionCacheKey */.nt),
|
|
574
|
+
qW: () => (/* reexport */ cache_tenant_util/* .cacheTenantId */.q),
|
|
513
575
|
ZD: () => (/* reexport */ escapeHtml),
|
|
514
576
|
qo: () => (/* reexport */ escapeHtmlVariables),
|
|
515
577
|
hX: () => (/* reexport */ extractFrontendUrl),
|
|
@@ -526,12 +588,17 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
526
588
|
lk: () => (/* reexport */ optional_module_util/* .loadOptionalModule */.l),
|
|
527
589
|
vf: () => (/* reexport */ localToUtc),
|
|
528
590
|
qe: () => (/* reexport */ event_pattern_util/* .matchEventPattern */.qe),
|
|
591
|
+
xY: () => (/* reexport */ permission_match_util/* .matchesPermission */.x),
|
|
592
|
+
RG: () => (/* reexport */ messageRef),
|
|
529
593
|
Ju: () => (/* reexport */ parseDurationToMs),
|
|
530
594
|
IN: () => (/* reexport */ event_pattern_util/* .sanitizeEventPayload */.IN),
|
|
531
595
|
v4: () => (/* reexport */ utcToLocal),
|
|
532
|
-
bE: () => (/* reexport */ validateCompanyOwnership)
|
|
596
|
+
bE: () => (/* reexport */ validateCompanyOwnership),
|
|
597
|
+
o0: () => (/* reexport */ withSavepoint)
|
|
533
598
|
});
|
|
534
599
|
|
|
600
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/cache-tenant.util.ts
|
|
601
|
+
var cache_tenant_util = __webpack_require__(154);
|
|
535
602
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/utils/date-time.util.ts
|
|
536
603
|
function getOffsetMinutes(utcDate, timezone) {
|
|
537
604
|
const extract = (tz)=>{
|
|
@@ -677,14 +744,26 @@ var event_pattern_util = __webpack_require__(456);
|
|
|
677
744
|
return escaped;
|
|
678
745
|
}
|
|
679
746
|
|
|
747
|
+
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/utils/message-ref.util.ts
|
|
748
|
+
function messageRef(messageKey, messageVariables) {
|
|
749
|
+
return messageVariables ? {
|
|
750
|
+
messageKey,
|
|
751
|
+
messageVariables
|
|
752
|
+
} : {
|
|
753
|
+
messageKey
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
|
|
680
757
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/optional-module.util.ts
|
|
681
758
|
var optional_module_util = __webpack_require__(368);
|
|
682
759
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/permission-cache-key.util.ts
|
|
683
760
|
var permission_cache_key_util = __webpack_require__(199);
|
|
761
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/permission-match.util.ts
|
|
762
|
+
var permission_match_util = __webpack_require__(788);
|
|
684
763
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
685
764
|
var common_ = __webpack_require__(157);
|
|
686
|
-
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/
|
|
687
|
-
var
|
|
765
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
766
|
+
var constants = __webpack_require__(43);
|
|
688
767
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/utils/query-helpers.util.ts
|
|
689
768
|
|
|
690
769
|
|
|
@@ -763,7 +842,7 @@ var message_keys = __webpack_require__(389);
|
|
|
763
842
|
if (entity.companyId && entity.companyId !== user.companyId) {
|
|
764
843
|
throw new common_.BadRequestException({
|
|
765
844
|
message: `${entityName} belongs to another company`,
|
|
766
|
-
messageKey:
|
|
845
|
+
messageKey: constants/* .AUTH_MESSAGES.ENTITY_BELOG_ANOTHER_COMPANY */.mK.ENTITY_BELOG_ANOTHER_COMPANY,
|
|
767
846
|
messageVariables: {
|
|
768
847
|
entity: entityName
|
|
769
848
|
}
|
|
@@ -771,11 +850,24 @@ var message_keys = __webpack_require__(389);
|
|
|
771
850
|
}
|
|
772
851
|
}
|
|
773
852
|
}
|
|
853
|
+
/**
|
|
854
|
+
* Runs `fn` inside a savepoint of an already-open transaction. A failure rolls back only what
|
|
855
|
+
* `fn` did, so the caller can swallow the error and keep using the transaction - without it,
|
|
856
|
+
* PostgreSQL aborts the whole transaction after any failed statement.
|
|
857
|
+
*/ async function withSavepoint(queryRunner, fn) {
|
|
858
|
+
await queryRunner.startTransaction();
|
|
859
|
+
try {
|
|
860
|
+
const result = await fn();
|
|
861
|
+
await queryRunner.commitTransaction();
|
|
862
|
+
return result;
|
|
863
|
+
} catch (error) {
|
|
864
|
+
await queryRunner.rollbackTransaction();
|
|
865
|
+
throw error;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
774
868
|
|
|
775
869
|
// EXTERNAL MODULE: external "@flusys/nestjs-core/config"
|
|
776
870
|
var config_ = __webpack_require__(307);
|
|
777
|
-
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
778
|
-
var constants = __webpack_require__(43);
|
|
779
871
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/utils/request.util.ts
|
|
780
872
|
|
|
781
873
|
|
|
@@ -856,7 +948,7 @@ var constants = __webpack_require__(43);
|
|
|
856
948
|
}
|
|
857
949
|
throw new common_.BadRequestException({
|
|
858
950
|
message: 'Unable to determine frontend URL from request',
|
|
859
|
-
messageKey:
|
|
951
|
+
messageKey: constants/* .ERROR_MESSAGES.VALIDATION */.UU.VALIDATION
|
|
860
952
|
});
|
|
861
953
|
}
|
|
862
954
|
function buildFrontendUrl(req, path) {
|
|
@@ -963,6 +1055,9 @@ function isExpired(expiresAt) {
|
|
|
963
1055
|
|
|
964
1056
|
|
|
965
1057
|
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
966
1061
|
},
|
|
967
1062
|
368(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
968
1063
|
/**
|
|
@@ -1018,6 +1113,22 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1018
1113
|
});
|
|
1019
1114
|
|
|
1020
1115
|
|
|
1116
|
+
},
|
|
1117
|
+
788(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1118
|
+
/** Whether `granted` covers `required`, honoring `*` (everything) and `prefix.*` (everything under prefix) wildcards */ function matchesPermission(granted, required) {
|
|
1119
|
+
if (granted.includes(required)) return true;
|
|
1120
|
+
for (const permission of granted){
|
|
1121
|
+
if (permission === '*') return true;
|
|
1122
|
+
if (permission.endsWith('.*') && required.startsWith(permission.slice(0, -1))) return true;
|
|
1123
|
+
}
|
|
1124
|
+
return false;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
1128
|
+
x: () => (matchesPermission)
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
|
|
1021
1132
|
},
|
|
1022
1133
|
307(module) {
|
|
1023
1134
|
|
|
@@ -1043,13 +1154,14 @@ import { __webpack_require__ } from '../runtime.js';
|
|
|
1043
1154
|
var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
|
|
1044
1155
|
import * as __rspack_chunk_1 from './index.js';
|
|
1045
1156
|
__webpack_require__.C(__rspack_chunk_1);
|
|
1046
|
-
var __webpack_exports__ = __webpack_exec__(
|
|
1157
|
+
var __webpack_exports__ = __webpack_exec__(528);var __webpack_exports__DEFAULT_COMPANY_PERMISSION_KEY_FORMAT = __webpack_exports__.s8;
|
|
1047
1158
|
var __webpack_exports__DEFAULT_USER_PERMISSION_KEY_FORMAT = __webpack_exports__.q6;
|
|
1048
1159
|
var __webpack_exports__applyCompanyFilter = __webpack_exports__.wf;
|
|
1049
1160
|
var __webpack_exports__buildCompanyWhereCondition = __webpack_exports__.kQ;
|
|
1050
1161
|
var __webpack_exports__buildCookieOptions = __webpack_exports__.fJ;
|
|
1051
1162
|
var __webpack_exports__buildFrontendUrl = __webpack_exports__.oV;
|
|
1052
1163
|
var __webpack_exports__buildPermissionCacheKey = __webpack_exports__.nt;
|
|
1164
|
+
var __webpack_exports__cacheTenantId = __webpack_exports__.qW;
|
|
1053
1165
|
var __webpack_exports__escapeHtml = __webpack_exports__.ZD;
|
|
1054
1166
|
var __webpack_exports__escapeHtmlVariables = __webpack_exports__.qo;
|
|
1055
1167
|
var __webpack_exports__extractFrontendUrl = __webpack_exports__.hX;
|
|
@@ -1066,8 +1178,11 @@ var __webpack_exports__isMultiWildcard = __webpack_exports__._c;
|
|
|
1066
1178
|
var __webpack_exports__loadOptionalModule = __webpack_exports__.lk;
|
|
1067
1179
|
var __webpack_exports__localToUtc = __webpack_exports__.vf;
|
|
1068
1180
|
var __webpack_exports__matchEventPattern = __webpack_exports__.qe;
|
|
1181
|
+
var __webpack_exports__matchesPermission = __webpack_exports__.xY;
|
|
1182
|
+
var __webpack_exports__messageRef = __webpack_exports__.RG;
|
|
1069
1183
|
var __webpack_exports__parseDurationToMs = __webpack_exports__.Ju;
|
|
1070
1184
|
var __webpack_exports__sanitizeEventPayload = __webpack_exports__.IN;
|
|
1071
1185
|
var __webpack_exports__utcToLocal = __webpack_exports__.v4;
|
|
1072
1186
|
var __webpack_exports__validateCompanyOwnership = __webpack_exports__.bE;
|
|
1073
|
-
|
|
1187
|
+
var __webpack_exports__withSavepoint = __webpack_exports__.o0;
|
|
1188
|
+
export { __webpack_exports__DEFAULT_COMPANY_PERMISSION_KEY_FORMAT as DEFAULT_COMPANY_PERMISSION_KEY_FORMAT, __webpack_exports__DEFAULT_USER_PERMISSION_KEY_FORMAT as DEFAULT_USER_PERMISSION_KEY_FORMAT, __webpack_exports__applyCompanyFilter as applyCompanyFilter, __webpack_exports__buildCompanyWhereCondition as buildCompanyWhereCondition, __webpack_exports__buildCookieOptions as buildCookieOptions, __webpack_exports__buildFrontendUrl as buildFrontendUrl, __webpack_exports__buildPermissionCacheKey as buildPermissionCacheKey, __webpack_exports__cacheTenantId as cacheTenantId, __webpack_exports__escapeHtml as escapeHtml, __webpack_exports__escapeHtmlVariables as escapeHtmlVariables, __webpack_exports__extractFrontendUrl as extractFrontendUrl, __webpack_exports__formatInTimezone as formatInTimezone, __webpack_exports__generateSecureToken as generateSecureToken, __webpack_exports__generateSlug as generateSlug, __webpack_exports__generateUniqueSlug as generateUniqueSlug, __webpack_exports__getTodayInTimezone as getTodayInTimezone, __webpack_exports__hasCompanyId as hasCompanyId, __webpack_exports__hashToken as hashToken, __webpack_exports__isBrowserRequest as isBrowserRequest, __webpack_exports__isExpired as isExpired, __webpack_exports__isMultiWildcard as isMultiWildcard, __webpack_exports__loadOptionalModule as loadOptionalModule, __webpack_exports__localToUtc as localToUtc, __webpack_exports__matchEventPattern as matchEventPattern, __webpack_exports__matchesPermission as matchesPermission, __webpack_exports__messageRef as messageRef, __webpack_exports__parseDurationToMs as parseDurationToMs, __webpack_exports__sanitizeEventPayload as sanitizeEventPayload, __webpack_exports__utcToLocal as utcToLocal, __webpack_exports__validateCompanyOwnership as validateCompanyOwnership, __webpack_exports__withSavepoint as withSavepoint };
|
package/index.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ import { DataSource, type EntityTarget, type ObjectLiteral, Repository } from 't
|
|
|
2
2
|
export interface IDataSourceProvider {
|
|
3
3
|
getRepository<T extends ObjectLiteral>(entity: EntityTarget<T>): Promise<Repository<T>>;
|
|
4
4
|
getDataSource(): Promise<DataSource>;
|
|
5
|
+
isMultiTenant?(): boolean;
|
|
6
|
+
getCurrentTenantId?(): string | null;
|
|
5
7
|
}
|
package/interfaces/index.d.ts
CHANGED
|
@@ -5,7 +5,10 @@ export * from './event-bus.interface.js';
|
|
|
5
5
|
export * from './event-manager-adapter.interface.js';
|
|
6
6
|
export * from './identity.interface.js';
|
|
7
7
|
export * from './logged-user-info.interface.js';
|
|
8
|
+
export * from './message-ref.interface.js';
|
|
8
9
|
export * from './module-config.interface.js';
|
|
9
10
|
export * from './notification-adapter.interface.js';
|
|
11
|
+
export * from './permission-action-registry.interface.js';
|
|
12
|
+
export * from './permission-resolver.interface.js';
|
|
10
13
|
export * from './permission.interface.js';
|
|
11
14
|
export * from './permission-sync-adapter.interface.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const PERMISSION_ACTION_REGISTRY = "PERMISSION_ACTION_REGISTRY";
|
|
2
|
+
export interface IPermissionActionInput {
|
|
3
|
+
code: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string | null;
|
|
6
|
+
parentCode?: string | null;
|
|
7
|
+
actionType?: 'BACKEND' | 'FRONTEND' | 'BOTH';
|
|
8
|
+
}
|
|
9
|
+
export interface IPermissionActionRegistry {
|
|
10
|
+
registerActions(actions: IPermissionActionInput[]): Promise<void>;
|
|
11
|
+
removeActionsByCodes(codes: string[]): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const PERMISSION_RESOLVER = "PERMISSION_RESOLVER";
|
|
2
|
+
export interface IPermissionScope {
|
|
3
|
+
userId: string;
|
|
4
|
+
companyId?: string | null;
|
|
5
|
+
branchId?: string | null;
|
|
6
|
+
}
|
|
7
|
+
export interface IPermissionResolver {
|
|
8
|
+
getPermissionCodes(scope: IPermissionScope): Promise<string[]>;
|
|
9
|
+
}
|
|
@@ -13,6 +13,10 @@ export declare const getRequestId: () => string | undefined;
|
|
|
13
13
|
export declare const getTenantId: () => string | undefined;
|
|
14
14
|
export declare const getUserId: () => string | undefined;
|
|
15
15
|
export declare const getCompanyId: () => string | undefined;
|
|
16
|
+
export declare function setRequestUser(user: {
|
|
17
|
+
id?: string;
|
|
18
|
+
companyId?: string;
|
|
19
|
+
} | undefined): void;
|
|
16
20
|
export declare class LoggerMiddleware implements NestMiddleware {
|
|
17
21
|
private readonly logger;
|
|
18
22
|
use(req: Request, res: Response, next: NextFunction): void;
|
|
@@ -9,6 +9,11 @@ export declare class SharedPermissionCacheService {
|
|
|
9
9
|
setPermissions(options: PermissionCacheKeyOptions, permissions: string[], ttl?: number): Promise<void>;
|
|
10
10
|
clearPermissions(options: PermissionCacheKeyOptions): Promise<void>;
|
|
11
11
|
hasPermission(options: PermissionCacheKeyOptions, requiredPermission: string): Promise<boolean>;
|
|
12
|
+
assertPermission(user: {
|
|
13
|
+
id?: string | null;
|
|
14
|
+
companyId?: string | null;
|
|
15
|
+
branchId?: string | null;
|
|
16
|
+
} | null | undefined, requiredPermission: string): Promise<void>;
|
|
12
17
|
isCacheConfigured(): boolean;
|
|
13
18
|
matchPermission(userPermissions: string[], requiredPermission: string): boolean;
|
|
14
19
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.1.0",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./fesm/index.js",
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
"types": "./modules/index.d.ts",
|
|
70
70
|
"import": "./fesm/modules/index.js"
|
|
71
71
|
},
|
|
72
|
+
"./pipes": {
|
|
73
|
+
"types": "./pipes/index.d.ts",
|
|
74
|
+
"import": "./fesm/pipes/index.js"
|
|
75
|
+
},
|
|
72
76
|
"./utils": {
|
|
73
77
|
"types": "./utils/index.d.ts",
|
|
74
78
|
"import": "./fesm/utils/index.js"
|
|
@@ -92,12 +96,14 @@
|
|
|
92
96
|
"class-validator": "^0.15.0",
|
|
93
97
|
"keyv": "^5.0.0",
|
|
94
98
|
"typeorm": "^0.3.0",
|
|
99
|
+
"typeorm-naming-strategies": "^4.1.0",
|
|
95
100
|
"winston": "^3.0.0",
|
|
101
|
+
"winston-transport": "^4.9.0",
|
|
96
102
|
"winston-daily-rotate-file": "^5.0.0",
|
|
97
103
|
"express": "^5.0.0",
|
|
98
104
|
"rxjs": "^7.8.0"
|
|
99
105
|
},
|
|
100
106
|
"dependencies": {
|
|
101
|
-
"@flusys/nestjs-core": "
|
|
107
|
+
"@flusys/nestjs-core": "9.1.0"
|
|
102
108
|
}
|
|
103
109
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ArgumentMetadata, type PipeTransform, type Type, type ValidationPipeOptions } from '@nestjs/common';
|
|
2
|
+
export declare const DEFAULT_VALIDATION_OPTIONS: ValidationPipeOptions;
|
|
3
|
+
export declare const AUDIT_BODY_KEYS: readonly ["createdById", "updatedById", "deletedById"];
|
|
4
|
+
export type AuditBodyKey = (typeof AUDIT_BODY_KEYS)[number];
|
|
5
|
+
type BodyItem = Record<string, unknown>;
|
|
6
|
+
export declare class DtoBodyValidationPipe implements PipeTransform {
|
|
7
|
+
private readonly resolveDto;
|
|
8
|
+
private readonly stampedKeys;
|
|
9
|
+
private readonly isArray;
|
|
10
|
+
private readonly options;
|
|
11
|
+
private readonly pipes;
|
|
12
|
+
constructor(resolveDto: (item: BodyItem) => Type<unknown>, stampedKeys: readonly AuditBodyKey[], isArray?: boolean, options?: ValidationPipeOptions);
|
|
13
|
+
static for(dto: Type<unknown>, stampedKeys: readonly AuditBodyKey[], isArray?: boolean): DtoBodyValidationPipe;
|
|
14
|
+
transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown>;
|
|
15
|
+
private validateItem;
|
|
16
|
+
private pipeFor;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
package/pipes/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dto-body-validation.pipe.js';
|
package/utils/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
export * from './cache-tenant.util.js';
|
|
1
2
|
export * from './date-time.util.js';
|
|
2
3
|
export * from './event-pattern.util.js';
|
|
3
4
|
export * from './html-sanitizer.util.js';
|
|
5
|
+
export * from './message-ref.util.js';
|
|
4
6
|
export * from './optional-module.util.js';
|
|
5
7
|
export * from './permission-cache-key.util.js';
|
|
8
|
+
export * from './permission-match.util.js';
|
|
6
9
|
export * from './query-helpers.util.js';
|
|
7
10
|
export * from './request.util.js';
|
|
8
11
|
export * from './string.util.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function matchesPermission(granted: readonly string[], required: string): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
1
|
+
import { type ObjectLiteral, type QueryRunner, SelectQueryBuilder } from 'typeorm';
|
|
2
2
|
import { type ILoggedUserInfo } from '../interfaces/index.js';
|
|
3
3
|
export interface ICompanyFilterConfig {
|
|
4
4
|
isCompanyFeatureEnabled: boolean;
|
|
@@ -14,3 +14,4 @@ export interface ICompanyEnabled {
|
|
|
14
14
|
}
|
|
15
15
|
export declare function hasCompanyId<T>(entity: T): entity is T & ICompanyEnabled;
|
|
16
16
|
export declare function validateCompanyOwnership<T>(entity: T, user: ILoggedUserInfo | null | undefined, isCompanyFeatureEnabled: boolean, entityName: string): void;
|
|
17
|
+
export declare function withSavepoint<T>(queryRunner: QueryRunner, fn: () => Promise<T>): Promise<T>;
|