@fiado/type-kit 3.471.0 → 3.472.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.
@@ -0,0 +1,25 @@
1
+ import 'reflect-metadata';
2
+ import { IsStringValueRecord } from '../../../src/common';
3
+ import { IsStringValueRecord as FromMessagesConnector } from '../../../src/messagesConnector/validators/IsStringValueRecord';
4
+
5
+ describe('IsStringValueRecord (common)', () => {
6
+ const validator = new IsStringValueRecord();
7
+ const args = {} as never;
8
+
9
+ it('acepta un mapa de strings', () => {
10
+ expect(validator.validate({ a: 'x', b: '' }, args)).toBe(true);
11
+ });
12
+
13
+ it('rechaza un valor que no es string', () => {
14
+ expect(validator.validate({ a: 1 }, args)).toBe(false);
15
+ });
16
+
17
+ it('rechaza null y valores que no son objeto', () => {
18
+ expect(validator.validate(null, args)).toBe(false);
19
+ expect(validator.validate('x', args)).toBe(false);
20
+ });
21
+
22
+ it('messagesConnector reexporta la misma clase', () => {
23
+ expect(FromMessagesConnector).toBe(IsStringValueRecord);
24
+ });
25
+ });
@@ -0,0 +1,55 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import { CreateTenantUserRequest } from '../../../../src/platformRbac/dtos/CreateTenantUserRequest';
5
+ import { UpdateTenantUserRequest } from '../../../../src/platformRbac/dtos/UpdateTenantUserRequest';
6
+ import { PermissionScope } from '../../../../src/platformRbac/enums/PermissionScope';
7
+
8
+ const createBase = {
9
+ email: 'agente@example.com',
10
+ roleId: 'role-agente',
11
+ scope: PermissionScope.LEVEL_1,
12
+ scopeRef: 'grp-1',
13
+ createdBy: 'admin-sub-1',
14
+ };
15
+ const updateBase = { actedBy: 'admin-sub-1' };
16
+
17
+ describe.each([
18
+ ['CreateTenantUserRequest', CreateTenantUserRequest, createBase],
19
+ ['UpdateTenantUserRequest', UpdateTenantUserRequest, updateBase],
20
+ ] as const)('%s.customFields', (_name, Dto, base) => {
21
+ const validateWith = async (customFields: unknown) =>
22
+ validate(plainToInstance(Dto as new () => object, { ...base, customFields }));
23
+
24
+ it('es opcional', async () => {
25
+ expect(await validate(plainToInstance(Dto as new () => object, base))).toEqual([]);
26
+ });
27
+
28
+ it('acepta un mapa de strings y lo conserva', async () => {
29
+ const dto = plainToInstance(Dto as new () => object, {
30
+ ...base,
31
+ customFields: { directory_id: 'dir-1', home_group_id: 'grp-1' },
32
+ }) as { customFields?: Record<string, string> };
33
+ expect(await validate(dto)).toEqual([]);
34
+ expect(dto.customFields).toEqual({ directory_id: 'dir-1', home_group_id: 'grp-1' });
35
+ });
36
+
37
+ it('acepta la cadena vacía (marca de borrado del rbac)', async () => {
38
+ expect(await validateWith({ directory_id: '' })).toEqual([]);
39
+ });
40
+
41
+ it('rechaza un valor que no es string', async () => {
42
+ const errors = await validateWith({ directory_id: 123 });
43
+ expect(errors.some((e) => e.property === 'customFields')).toBe(true);
44
+ });
45
+
46
+ it('rechaza un arreglo', async () => {
47
+ const errors = await validateWith(['dir-1']);
48
+ expect(errors.some((e) => e.property === 'customFields')).toBe(true);
49
+ });
50
+
51
+ it('rechaza un string suelto', async () => {
52
+ const errors = await validateWith('dir-1');
53
+ expect(errors.some((e) => e.property === 'customFields')).toBe(true);
54
+ });
55
+ });
@@ -1,4 +1,5 @@
1
1
  export * from './decorators/Trim';
2
+ export * from './validators/IsStringValueRecord';
2
3
  export * from './dtos/ProcessValidationResultDto';
3
4
  export * from './enums/ProcessValidationEnum';
4
5
  export * from './enums/ProcessResultEnum';
@@ -16,6 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  //decorators
18
18
  __exportStar(require("./decorators/Trim"), exports);
19
+ //validators
20
+ __exportStar(require("./validators/IsStringValueRecord"), exports);
19
21
  //dtos
20
22
  __exportStar(require("./dtos/ProcessValidationResultDto"), exports);
21
23
  //Enums
@@ -0,0 +1,5 @@
1
+ import { ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
2
+ export declare class IsStringValueRecord implements ValidatorConstraintInterface {
3
+ validate(value: unknown, _args: ValidationArguments): boolean;
4
+ defaultMessage(_args: ValidationArguments): string;
5
+ }
@@ -0,0 +1,25 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.IsStringValueRecord = void 0;
10
+ const class_validator_1 = require("class-validator");
11
+ // Valida que un objeto sea un mapa clave → string.
12
+ let IsStringValueRecord = class IsStringValueRecord {
13
+ validate(value, _args) {
14
+ if (!value || typeof value !== 'object')
15
+ return false;
16
+ return Object.values(value).every(v => typeof v === 'string');
17
+ }
18
+ defaultMessage(_args) {
19
+ return 'All values in variables must be strings';
20
+ }
21
+ };
22
+ exports.IsStringValueRecord = IsStringValueRecord;
23
+ exports.IsStringValueRecord = IsStringValueRecord = __decorate([
24
+ (0, class_validator_1.ValidatorConstraint)({ name: 'IsStringValueRecord', async: false })
25
+ ], IsStringValueRecord);
@@ -1,5 +1 @@
1
- import { ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
2
- export declare class IsStringValueRecord implements ValidatorConstraintInterface {
3
- validate(value: unknown, _args: ValidationArguments): boolean;
4
- defaultMessage(_args: ValidationArguments): string;
5
- }
1
+ export { IsStringValueRecord } from '../../common/validators/IsStringValueRecord';
@@ -1,24 +1,6 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
9
3
  exports.IsStringValueRecord = void 0;
10
- const class_validator_1 = require("class-validator");
11
- let IsStringValueRecord = class IsStringValueRecord {
12
- validate(value, _args) {
13
- if (!value || typeof value !== 'object')
14
- return false;
15
- return Object.values(value).every(v => typeof v === 'string');
16
- }
17
- defaultMessage(_args) {
18
- return 'All values in variables must be strings';
19
- }
20
- };
21
- exports.IsStringValueRecord = IsStringValueRecord;
22
- exports.IsStringValueRecord = IsStringValueRecord = __decorate([
23
- (0, class_validator_1.ValidatorConstraint)({ name: 'IsStringValueRecord', async: false })
24
- ], IsStringValueRecord);
4
+ // Movido a common: se reexporta para no romper a quien importa desde messagesConnector.
5
+ var IsStringValueRecord_1 = require("../../common/validators/IsStringValueRecord");
6
+ Object.defineProperty(exports, "IsStringValueRecord", { enumerable: true, get: function () { return IsStringValueRecord_1.IsStringValueRecord; } });
@@ -8,6 +8,7 @@ import { PermissionScope } from '../enums/PermissionScope';
8
8
  * - Idempotente por identidad Cognito.
9
9
  * - `scope`/`scopeRef` = grant del rol (ej. LEVEL_3 + storeId para un vendedor de tienda).
10
10
  * - `createdBy` = cognitoSub del admin real (audit + grantedBy del assignment).
11
+ * - `customFields` = valores de los campos personalizados del tenant; si el correo ya tiene usuario, se fusionan.
11
12
  */
12
13
  export declare class CreateTenantUserRequest {
13
14
  email: string;
@@ -16,4 +17,7 @@ export declare class CreateTenantUserRequest {
16
17
  scope: PermissionScope;
17
18
  scopeRef: string;
18
19
  createdBy: string;
20
+ customFields?: {
21
+ [key: string]: string;
22
+ };
19
23
  }
@@ -13,6 +13,7 @@ exports.CreateTenantUserRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const PermissionScope_1 = require("../enums/PermissionScope");
16
+ const IsStringValueRecord_1 = require("../../common/validators/IsStringValueRecord");
16
17
  /**
17
18
  * Body del POST /internal/tenants/{tenantId}/users (endpoint privado, VPC/ANONIMUS). `tenantId` viaja en el path.
18
19
  * Provisiona Cognito + SharedUser + RoleAssignment (rol + scopeRef) en RBAC — reusa UserProvisioningService.
@@ -22,6 +23,7 @@ const PermissionScope_1 = require("../enums/PermissionScope");
22
23
  * - Idempotente por identidad Cognito.
23
24
  * - `scope`/`scopeRef` = grant del rol (ej. LEVEL_3 + storeId para un vendedor de tienda).
24
25
  * - `createdBy` = cognitoSub del admin real (audit + grantedBy del assignment).
26
+ * - `customFields` = valores de los campos personalizados del tenant; si el correo ya tiene usuario, se fusionan.
25
27
  */
26
28
  class CreateTenantUserRequest {
27
29
  }
@@ -61,3 +63,10 @@ __decorate([
61
63
  (0, class_validator_1.IsNotEmpty)(),
62
64
  __metadata("design:type", String)
63
65
  ], CreateTenantUserRequest.prototype, "createdBy", void 0);
66
+ __decorate([
67
+ (0, class_transformer_1.Expose)(),
68
+ (0, class_validator_1.IsOptional)(),
69
+ (0, class_validator_1.IsObject)(),
70
+ (0, class_validator_1.Validate)(IsStringValueRecord_1.IsStringValueRecord, { message: 'customFields: todos los valores deben ser string' }),
71
+ __metadata("design:type", Object)
72
+ ], CreateTenantUserRequest.prototype, "customFields", void 0);
@@ -1,8 +1,11 @@
1
1
  /**
2
- * Body del PUT que renombra a un usuario. El correo es inmutable en el rbac y el grupo se mueve
3
- * reasignando el rol, así que aquí no viaja ninguno de los dos.
2
+ * Body del PUT que edita a un usuario: nombre y campos personalizados. `customFields` se fusiona con los
3
+ * actuales (solo cambian las claves enviadas; "" borra una). Correo y grupo no viajan aquí.
4
4
  */
5
5
  export declare class UpdateTenantUserRequest {
6
6
  displayName?: string;
7
+ customFields?: {
8
+ [key: string]: string;
9
+ };
7
10
  actedBy: string;
8
11
  }
@@ -12,9 +12,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.UpdateTenantUserRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const IsStringValueRecord_1 = require("../../common/validators/IsStringValueRecord");
15
16
  /**
16
- * Body del PUT que renombra a un usuario. El correo es inmutable en el rbac y el grupo se mueve
17
- * reasignando el rol, así que aquí no viaja ninguno de los dos.
17
+ * Body del PUT que edita a un usuario: nombre y campos personalizados. `customFields` se fusiona con los
18
+ * actuales (solo cambian las claves enviadas; "" borra una). Correo y grupo no viajan aquí.
18
19
  */
19
20
  class UpdateTenantUserRequest {
20
21
  }
@@ -27,6 +28,13 @@ __decorate([
27
28
  (0, class_validator_1.MaxLength)(120),
28
29
  __metadata("design:type", String)
29
30
  ], UpdateTenantUserRequest.prototype, "displayName", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsOptional)(),
34
+ (0, class_validator_1.IsObject)(),
35
+ (0, class_validator_1.Validate)(IsStringValueRecord_1.IsStringValueRecord, { message: 'customFields: todos los valores deben ser string' }),
36
+ __metadata("design:type", Object)
37
+ ], UpdateTenantUserRequest.prototype, "customFields", void 0);
30
38
  __decorate([
31
39
  (0, class_transformer_1.Expose)(),
32
40
  (0, class_validator_1.IsString)(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.471.0",
3
+ "version": "3.472.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -1,6 +1,9 @@
1
1
  //decorators
2
2
  export * from './decorators/Trim';
3
3
 
4
+ //validators
5
+ export * from './validators/IsStringValueRecord';
6
+
4
7
  //dtos
5
8
  export * from './dtos/ProcessValidationResultDto';
6
9
 
@@ -0,0 +1,13 @@
1
+ import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
2
+
3
+ // Valida que un objeto sea un mapa clave → string.
4
+ @ValidatorConstraint({ name: 'IsStringValueRecord', async: false })
5
+ export class IsStringValueRecord implements ValidatorConstraintInterface {
6
+ validate(value: unknown, _args: ValidationArguments): boolean {
7
+ if (!value || typeof value !== 'object') return false;
8
+ return Object.values(value as Record<string, unknown>).every(v => typeof v === 'string');
9
+ }
10
+ defaultMessage(_args: ValidationArguments): string {
11
+ return 'All values in variables must be strings';
12
+ }
13
+ }
@@ -1,12 +1,2 @@
1
- import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
2
-
3
- @ValidatorConstraint({ name: 'IsStringValueRecord', async: false })
4
- export class IsStringValueRecord implements ValidatorConstraintInterface {
5
- validate(value: unknown, _args: ValidationArguments): boolean {
6
- if (!value || typeof value !== 'object') return false;
7
- return Object.values(value as Record<string, unknown>).every(v => typeof v === 'string');
8
- }
9
- defaultMessage(_args: ValidationArguments): string {
10
- return 'All values in variables must be strings';
11
- }
12
- }
1
+ // Movido a common: se reexporta para no romper a quien importa desde messagesConnector.
2
+ export { IsStringValueRecord } from '../../common/validators/IsStringValueRecord';
@@ -1,6 +1,7 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsEmail, IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
2
+ import { IsEmail, IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, Validate } from 'class-validator';
3
3
  import { PermissionScope } from '../enums/PermissionScope';
4
+ import { IsStringValueRecord } from '../../common/validators/IsStringValueRecord';
4
5
 
5
6
  /**
6
7
  * Body del POST /internal/tenants/{tenantId}/users (endpoint privado, VPC/ANONIMUS). `tenantId` viaja en el path.
@@ -11,6 +12,7 @@ import { PermissionScope } from '../enums/PermissionScope';
11
12
  * - Idempotente por identidad Cognito.
12
13
  * - `scope`/`scopeRef` = grant del rol (ej. LEVEL_3 + storeId para un vendedor de tienda).
13
14
  * - `createdBy` = cognitoSub del admin real (audit + grantedBy del assignment).
15
+ * - `customFields` = valores de los campos personalizados del tenant; si el correo ya tiene usuario, se fusionan.
14
16
  */
15
17
  export class CreateTenantUserRequest {
16
18
  @Expose() @IsEmail() email!: string;
@@ -19,4 +21,9 @@ export class CreateTenantUserRequest {
19
21
  @Expose() @IsEnum(PermissionScope) scope!: PermissionScope;
20
22
  @Expose() @IsString() @IsNotEmpty() scopeRef!: string;
21
23
  @Expose() @IsString() @IsNotEmpty() createdBy!: string;
24
+ @Expose()
25
+ @IsOptional()
26
+ @IsObject()
27
+ @Validate(IsStringValueRecord, { message: 'customFields: todos los valores deben ser string' })
28
+ customFields?: { [key: string]: string };
22
29
  }
@@ -1,11 +1,17 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
2
+ import { IsNotEmpty, IsObject, IsOptional, IsString, MaxLength, Validate } from 'class-validator';
3
+ import { IsStringValueRecord } from '../../common/validators/IsStringValueRecord';
3
4
 
4
5
  /**
5
- * Body del PUT que renombra a un usuario. El correo es inmutable en el rbac y el grupo se mueve
6
- * reasignando el rol, así que aquí no viaja ninguno de los dos.
6
+ * Body del PUT que edita a un usuario: nombre y campos personalizados. `customFields` se fusiona con los
7
+ * actuales (solo cambian las claves enviadas; "" borra una). Correo y grupo no viajan aquí.
7
8
  */
8
9
  export class UpdateTenantUserRequest {
9
10
  @Expose() @IsOptional() @IsString() @IsNotEmpty() @MaxLength(120) displayName?: string;
11
+ @Expose()
12
+ @IsOptional()
13
+ @IsObject()
14
+ @Validate(IsStringValueRecord, { message: 'customFields: todos los valores deben ser string' })
15
+ customFields?: { [key: string]: string };
10
16
  @Expose() @IsString() @IsNotEmpty() actedBy!: string;
11
17
  }