@fiado/type-kit 3.70.0 → 3.71.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.
@@ -38,6 +38,19 @@ describe('CreateUserRequest', () => {
38
38
  expect(errors.some(e => e.property === 'tenantId')).toBe(true);
39
39
  });
40
40
 
41
+ // userPoolId + region pasan a ser OPCIONALES: el front del alta de usuario PLATFORM deja de
42
+ // mandarlos y el backend (platform-rbac-business) los resuelve de la config del tenant 'platform'.
43
+ // Quedan en el DTO por compatibilidad con los demás callers del connector que SÍ los proveen.
44
+ it('valida sin userPoolId ni region (alta platform — el backend los resuelve)', async () => {
45
+ const dto = plainToInstance(CreateUserRequest, {
46
+ email: 'user@acme.com',
47
+ tenantId: 'platform',
48
+ });
49
+ const errors = await validate(dto);
50
+ expect(errors.some(e => e.property === 'userPoolId')).toBe(false);
51
+ expect(errors.some(e => e.property === 'region')).toBe(false);
52
+ });
53
+
41
54
  it('preserva los campos opcionales legítimos', async () => {
42
55
  const dto = plainToInstance(CreateUserRequest, {
43
56
  ...valid,
@@ -0,0 +1,22 @@
1
+ import 'reflect-metadata';
2
+ import type { AuthContext, EffectivePermissionsResponse } from '../../../../src/platformRbac/index';
3
+
4
+ it('AuthContext acepta los campos opcionales del token-as-cache', () => {
5
+ const ctx: AuthContext = {
6
+ cognitoSub: 's',
7
+ tenantId: 't',
8
+ email: 'e',
9
+ roleAssignments: [],
10
+ permissions: [],
11
+ resolvedAt: 'now',
12
+ permBits: 'AAA',
13
+ permVer: 1,
14
+ permsEpoch: 3,
15
+ };
16
+ expect(ctx.permVer).toBe(1);
17
+ });
18
+
19
+ it('EffectivePermissionsResponse tiene permissions + roleAssignments + epoch', () => {
20
+ const r: EffectivePermissionsResponse = { permissions: [], roleAssignments: [], permsEpoch: 0 };
21
+ expect(r.permsEpoch).toBe(0);
22
+ });
@@ -0,0 +1,98 @@
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
+
3
+ exports[`PERMISSION_BIT_ORDER PERMS_VERSION es número estable 1`] = `4037934643`;
4
+
5
+ exports[`PERMISSION_BIT_ORDER append-only: snapshot del ORDEN COMPLETO (rompe ante cualquier reorden/inserción) 1`] = `
6
+ [
7
+ "rbac.catalog.manage",
8
+ "platform.tenant.create",
9
+ "platform.tenant.list",
10
+ "platform.tenant.view",
11
+ "platform.tenant.update",
12
+ "platform.tenant.suspend",
13
+ "platform.tenant.activate",
14
+ "platform.tenant.admin.replace",
15
+ "platform.cognito.pool.manage",
16
+ "platform.cognito.pool.list",
17
+ "platform.user.create",
18
+ "platform.user.list",
19
+ "platform.user.view",
20
+ "platform.user.update",
21
+ "platform.user.disable",
22
+ "platform.user.enable",
23
+ "platform.user.delete",
24
+ "platform.role.create",
25
+ "platform.role.list",
26
+ "platform.role.update",
27
+ "platform.role.delete",
28
+ "platform.audit.view",
29
+ "tenant.user.create",
30
+ "tenant.user.create.lateral",
31
+ "tenant.user.read",
32
+ "tenant.user.status",
33
+ "tenant.user.list",
34
+ "tenant.user.view",
35
+ "tenant.user.update",
36
+ "tenant.user.disable",
37
+ "tenant.user.enable",
38
+ "tenant.user.delete",
39
+ "tenant.user.mfa.reset",
40
+ "tenant.user.password.reset",
41
+ "tenant.role.create",
42
+ "tenant.role.list",
43
+ "tenant.role.update",
44
+ "tenant.role.delete",
45
+ "tenant.role.view",
46
+ "tenant.role.assign",
47
+ "tenant.role.revoke",
48
+ "tenant.security.policy.view",
49
+ "tenant.security.policy.manage",
50
+ "tenant.branding.manage",
51
+ "tenant.audit.view",
52
+ "retail.user.create",
53
+ "retail.user.create.lateral",
54
+ "retail.user.read",
55
+ "retail.user.update",
56
+ "retail.user.status",
57
+ "retail.user.delete",
58
+ "retail.user.password.reset",
59
+ "retail.user.mfa.reset",
60
+ "retail.product.create",
61
+ "retail.product.list",
62
+ "retail.product.view",
63
+ "retail.product.update",
64
+ "retail.product.delete",
65
+ "retail.product.mdm_config",
66
+ "retail.inventory.list",
67
+ "retail.inventory.view",
68
+ "retail.inventory.update",
69
+ "retail.sale.create",
70
+ "retail.sale.list",
71
+ "retail.sale.cancel",
72
+ "retail.store.manage",
73
+ "retail.retailer.manage",
74
+ "lend.credit.create",
75
+ "lend.credit.list",
76
+ "lend.credit.view",
77
+ "lend.credit.update",
78
+ "lend.credit.liquidate",
79
+ "lend.credit.restructure",
80
+ "lend.payment.apply",
81
+ "lend.payment.list",
82
+ "lend.payment.reverse",
83
+ "lend.installment.view",
84
+ "mdm.device.enroll",
85
+ "mdm.device.release",
86
+ "mdm.device.archive",
87
+ "mdm.device.deactivate",
88
+ "mdm.device.lock.manual",
89
+ "mdm.device.unlock.manual",
90
+ "mdm.device.pin_unlock",
91
+ "mdm.device.extend_validity",
92
+ "mdm.device.notify",
93
+ "mdm.device.status.view",
94
+ "mdm.operation_log.view",
95
+ "mdm.test",
96
+ "pay.transaction.view",
97
+ ]
98
+ `;
@@ -0,0 +1,36 @@
1
+ import {
2
+ Permission,
3
+ PERMISSION_BIT_ORDER,
4
+ PERMS_VERSION,
5
+ permissionsToBits,
6
+ bitsToPermissions,
7
+ } from '../../../../src/platformRbac/enums/Permission';
8
+
9
+ describe('PERMISSION_BIT_ORDER', () => {
10
+ it('contiene TODOS los valores del enum Permission', () => {
11
+ const enumVals = Object.values(Permission) as string[];
12
+ expect([...PERMISSION_BIT_ORDER].sort()).toEqual([...enumVals].sort());
13
+ });
14
+ it('append-only: snapshot del ORDEN COMPLETO (rompe ante cualquier reorden/inserción)', () => {
15
+ // Snapshot del array entero, NO un prefijo: un reorden del índice 11+ o una inserción
16
+ // intermedia desalinea todos los tokens emitidos. Si esto rompe, fue intencional → -u consciente.
17
+ expect(PERMISSION_BIT_ORDER).toMatchSnapshot();
18
+ });
19
+ it('PERMS_VERSION es número estable', () => {
20
+ expect(typeof PERMS_VERSION).toBe('number');
21
+ expect(PERMS_VERSION).toMatchSnapshot();
22
+ });
23
+ it('round-trip permisos ↔ bits', () => {
24
+ const perms = [
25
+ PERMISSION_BIT_ORDER[0],
26
+ PERMISSION_BIT_ORDER[5],
27
+ PERMISSION_BIT_ORDER[PERMISSION_BIT_ORDER.length - 1],
28
+ ];
29
+ const bits = permissionsToBits(perms);
30
+ expect(typeof bits).toBe('string');
31
+ expect(new Set(bitsToPermissions(bits))).toEqual(new Set(perms));
32
+ });
33
+ it('bitsToPermissions tolera basura → []', () => {
34
+ expect(bitsToPermissions('')).toEqual([]);
35
+ });
36
+ });
@@ -1,6 +1,6 @@
1
1
  export declare class CreateUserRequest {
2
- userPoolId: string;
3
- region: string;
2
+ userPoolId?: string;
3
+ region?: string;
4
4
  email: string;
5
5
  displayName?: string;
6
6
  tenantId: string;
@@ -17,14 +17,14 @@ class CreateUserRequest {
17
17
  exports.CreateUserRequest = CreateUserRequest;
18
18
  __decorate([
19
19
  (0, class_transformer_1.Expose)(),
20
+ (0, class_validator_1.IsOptional)(),
20
21
  (0, class_validator_1.IsString)(),
21
- (0, class_validator_1.IsNotEmpty)(),
22
22
  __metadata("design:type", String)
23
23
  ], CreateUserRequest.prototype, "userPoolId", void 0);
24
24
  __decorate([
25
25
  (0, class_transformer_1.Expose)(),
26
+ (0, class_validator_1.IsOptional)(),
26
27
  (0, class_validator_1.IsString)(),
27
- (0, class_validator_1.IsNotEmpty)(),
28
28
  __metadata("design:type", String)
29
29
  ], CreateUserRequest.prototype, "region", void 0);
30
30
  __decorate([
@@ -18,4 +18,10 @@ export interface AuthContext {
18
18
  permissions: Permission[];
19
19
  resolvedAt: string;
20
20
  issuer?: string;
21
+ /** Bitset base64url de permisos efectivos (token-as-cache). Ausente → fallback al resolver/claim. */
22
+ permBits?: string;
23
+ /** Versión del catálogo (PERMS_VERSION) con la que se construyó permBits. */
24
+ permVer?: number;
25
+ /** Epoch de permisos del tenant al momento de emitir el token. */
26
+ permsEpoch?: number;
21
27
  }
@@ -0,0 +1,8 @@
1
+ import type { Permission } from '../enums/Permission';
2
+ import type { RoleAssignmentInfo } from './RoleAssignmentInfo';
3
+ /** Respuesta de platform-rbac-business /internal/effective-permissions (consumida por jwt-inyector). */
4
+ export interface EffectivePermissionsResponse {
5
+ permissions: Permission[];
6
+ roleAssignments: RoleAssignmentInfo[];
7
+ permsEpoch: number;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -102,3 +102,16 @@ export declare enum Permission {
102
102
  MDM_TEST = "mdm.test",
103
103
  PAY_TRANSACTION_VIEW = "pay.transaction.view"
104
104
  }
105
+ /**
106
+ * Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
107
+ * Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
108
+ * deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
109
+ * Derivado explícitamente (no Object.values, frágil ante edición del enum).
110
+ */
111
+ export declare const PERMISSION_BIT_ORDER: readonly Permission[];
112
+ /** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
113
+ export declare const PERMS_VERSION: number;
114
+ /** Comprime un set de permisos a bitset base64url. */
115
+ export declare function permissionsToBits(perms: readonly Permission[]): string;
116
+ /** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
117
+ export declare function bitsToPermissions(bits: string): Permission[];
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Permission = void 0;
3
+ exports.PERMS_VERSION = exports.PERMISSION_BIT_ORDER = exports.Permission = void 0;
4
+ exports.permissionsToBits = permissionsToBits;
5
+ exports.bitsToPermissions = bitsToPermissions;
4
6
  /**
5
7
  * Catálogo universal de permisos del sistema RBAC Fiado.
6
8
  *
@@ -135,3 +137,140 @@ var Permission;
135
137
  // ====================================================
136
138
  Permission["PAY_TRANSACTION_VIEW"] = "pay.transaction.view";
137
139
  })(Permission || (exports.Permission = Permission = {}));
140
+ /**
141
+ * Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
142
+ * Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
143
+ * deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
144
+ * Derivado explícitamente (no Object.values, frágil ante edición del enum).
145
+ */
146
+ exports.PERMISSION_BIT_ORDER = [
147
+ Permission.RBAC_CATALOG_MANAGE,
148
+ Permission.PLATFORM_TENANT_CREATE,
149
+ Permission.PLATFORM_TENANT_LIST,
150
+ Permission.PLATFORM_TENANT_VIEW,
151
+ Permission.PLATFORM_TENANT_UPDATE,
152
+ Permission.PLATFORM_TENANT_SUSPEND,
153
+ Permission.PLATFORM_TENANT_ACTIVATE,
154
+ Permission.PLATFORM_TENANT_ADMIN_REPLACE,
155
+ Permission.PLATFORM_COGNITO_POOL_MANAGE,
156
+ Permission.PLATFORM_COGNITO_POOL_LIST,
157
+ Permission.PLATFORM_USER_CREATE,
158
+ Permission.PLATFORM_USER_LIST,
159
+ Permission.PLATFORM_USER_VIEW,
160
+ Permission.PLATFORM_USER_UPDATE,
161
+ Permission.PLATFORM_USER_DISABLE,
162
+ Permission.PLATFORM_USER_ENABLE,
163
+ Permission.PLATFORM_USER_DELETE,
164
+ Permission.PLATFORM_ROLE_CREATE,
165
+ Permission.PLATFORM_ROLE_LIST,
166
+ Permission.PLATFORM_ROLE_UPDATE,
167
+ Permission.PLATFORM_ROLE_DELETE,
168
+ Permission.PLATFORM_AUDIT_VIEW,
169
+ Permission.TENANT_USER_CREATE,
170
+ Permission.TENANT_USER_CREATE_LATERAL,
171
+ Permission.TENANT_USER_READ,
172
+ Permission.TENANT_USER_STATUS,
173
+ Permission.TENANT_USER_LIST,
174
+ Permission.TENANT_USER_VIEW,
175
+ Permission.TENANT_USER_UPDATE,
176
+ Permission.TENANT_USER_DISABLE,
177
+ Permission.TENANT_USER_ENABLE,
178
+ Permission.TENANT_USER_DELETE,
179
+ Permission.TENANT_USER_MFA_RESET,
180
+ Permission.TENANT_USER_PASSWORD_RESET,
181
+ Permission.TENANT_ROLE_CREATE,
182
+ Permission.TENANT_ROLE_LIST,
183
+ Permission.TENANT_ROLE_UPDATE,
184
+ Permission.TENANT_ROLE_DELETE,
185
+ Permission.TENANT_ROLE_VIEW,
186
+ Permission.TENANT_ROLE_ASSIGN,
187
+ Permission.TENANT_ROLE_REVOKE,
188
+ Permission.TENANT_SECURITY_POLICY_VIEW,
189
+ Permission.TENANT_SECURITY_POLICY_MANAGE,
190
+ Permission.TENANT_BRANDING_MANAGE,
191
+ Permission.TENANT_AUDIT_VIEW,
192
+ Permission.RETAIL_USER_CREATE,
193
+ Permission.RETAIL_USER_CREATE_LATERAL,
194
+ Permission.RETAIL_USER_READ,
195
+ Permission.RETAIL_USER_UPDATE,
196
+ Permission.RETAIL_USER_STATUS,
197
+ Permission.RETAIL_USER_DELETE,
198
+ Permission.RETAIL_USER_PASSWORD_RESET,
199
+ Permission.RETAIL_USER_MFA_RESET,
200
+ Permission.RETAIL_PRODUCT_CREATE,
201
+ Permission.RETAIL_PRODUCT_LIST,
202
+ Permission.RETAIL_PRODUCT_VIEW,
203
+ Permission.RETAIL_PRODUCT_UPDATE,
204
+ Permission.RETAIL_PRODUCT_DELETE,
205
+ Permission.RETAIL_PRODUCT_MDM_CONFIG,
206
+ Permission.RETAIL_INVENTORY_LIST,
207
+ Permission.RETAIL_INVENTORY_VIEW,
208
+ Permission.RETAIL_INVENTORY_UPDATE,
209
+ Permission.RETAIL_SALE_CREATE,
210
+ Permission.RETAIL_SALE_LIST,
211
+ Permission.RETAIL_SALE_CANCEL,
212
+ Permission.RETAIL_STORE_MANAGE,
213
+ Permission.RETAIL_RETAILER_MANAGE,
214
+ Permission.LEND_CREDIT_CREATE,
215
+ Permission.LEND_CREDIT_LIST,
216
+ Permission.LEND_CREDIT_VIEW,
217
+ Permission.LEND_CREDIT_UPDATE,
218
+ Permission.LEND_CREDIT_LIQUIDATE,
219
+ Permission.LEND_CREDIT_RESTRUCTURE,
220
+ Permission.LEND_PAYMENT_APPLY,
221
+ Permission.LEND_PAYMENT_LIST,
222
+ Permission.LEND_PAYMENT_REVERSE,
223
+ Permission.LEND_INSTALLMENT_VIEW,
224
+ Permission.MDM_DEVICE_ENROLL,
225
+ Permission.MDM_DEVICE_RELEASE,
226
+ Permission.MDM_DEVICE_ARCHIVE,
227
+ Permission.MDM_DEVICE_DEACTIVATE,
228
+ Permission.MDM_DEVICE_LOCK_MANUAL,
229
+ Permission.MDM_DEVICE_UNLOCK_MANUAL,
230
+ Permission.MDM_DEVICE_PIN_UNLOCK,
231
+ Permission.MDM_DEVICE_EXTEND_VALIDITY,
232
+ Permission.MDM_DEVICE_NOTIFY,
233
+ Permission.MDM_DEVICE_STATUS_VIEW,
234
+ Permission.MDM_OPERATION_LOG_VIEW,
235
+ Permission.MDM_TEST,
236
+ Permission.PAY_TRANSACTION_VIEW,
237
+ ];
238
+ function djb2(input) {
239
+ let h = 5381;
240
+ for (let i = 0; i < input.length; i++)
241
+ h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;
242
+ return h;
243
+ }
244
+ /** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
245
+ exports.PERMS_VERSION = djb2(exports.PERMISSION_BIT_ORDER.join('|'));
246
+ const BIT_INDEX = new Map(exports.PERMISSION_BIT_ORDER.map((p, i) => [p, i]));
247
+ /** Comprime un set de permisos a bitset base64url. */
248
+ function permissionsToBits(perms) {
249
+ const bytes = new Uint8Array(Math.ceil(exports.PERMISSION_BIT_ORDER.length / 8));
250
+ for (const p of perms) {
251
+ const idx = BIT_INDEX.get(p);
252
+ if (idx === undefined)
253
+ continue;
254
+ bytes[idx >> 3] |= 1 << (idx & 7);
255
+ }
256
+ return Buffer.from(bytes).toString('base64url');
257
+ }
258
+ /** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
259
+ function bitsToPermissions(bits) {
260
+ if (typeof bits !== 'string' || bits.length === 0)
261
+ return [];
262
+ let bytes;
263
+ try {
264
+ bytes = Buffer.from(bits, 'base64url');
265
+ }
266
+ catch {
267
+ return [];
268
+ }
269
+ const out = [];
270
+ for (let i = 0; i < exports.PERMISSION_BIT_ORDER.length; i++) {
271
+ const byte = bytes[i >> 3] ?? 0;
272
+ if (byte & (1 << (i & 7)))
273
+ out.push(exports.PERMISSION_BIT_ORDER[i]);
274
+ }
275
+ return out;
276
+ }
@@ -1,9 +1,10 @@
1
- export { Permission } from './enums/Permission';
1
+ export { Permission, PERMISSION_BIT_ORDER, PERMS_VERSION, permissionsToBits, bitsToPermissions, } from './enums/Permission';
2
2
  export { PermissionScope } from './enums/PermissionScope';
3
3
  export { PermissionCategory } from './enums/PermissionCategory';
4
4
  export type { AuthContext } from './dtos/AuthContext';
5
5
  export type { RoleAssignmentInfo } from './dtos/RoleAssignmentInfo';
6
6
  export type { PermissionMeta } from './dtos/PermissionMeta';
7
+ export type { EffectivePermissionsResponse } from './dtos/EffectivePermissionsResponse';
7
8
  export * from './enums/MfaMethodEnum';
8
9
  export * from './enums/ChallengeNameEnum';
9
10
  export * from './auth/DefineNextChallengeRequest';
@@ -5,9 +5,9 @@
5
5
  // del platform-rbac-business documenta la migración futura de los 4 símbolos cross-cutting
6
6
  // (Permission, PermissionScope, AuthContext, RoleAssignmentInfo) de aquí a `rbac/`.
7
7
  //
8
- // En Fase 1.A los DTOs propios del rbac-business (CreateTenantRequest, AssignRoleRequest,
9
- // EffectivePermissionsResponse, etc.) NO viven en este módulo todavía — se agregan en
10
- // Fase 1.B cuando los managers que los consumen se implementen.
8
+ // Los DTOs propios del rbac-business se van agregando a medida que los flujos los necesitan.
9
+ // EffectivePermissionsResponse ya vive acá (lo consume jwt-inyector vía /internal/effective-permissions).
10
+ // Otros DTOs aún pendientes se sumarán cuando los managers que los consumen se implementen.
11
11
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
12
  if (k2 === undefined) k2 = k;
13
13
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -23,9 +23,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
23
23
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.scopeRankOrder = exports.tableSuffixForLevel = exports.levelsOf = exports.TENANT_TYPES = exports.TenantType = exports.AuthorizeDenyReason = exports.PermissionCategory = exports.PermissionScope = exports.Permission = void 0;
26
+ exports.scopeRankOrder = exports.tableSuffixForLevel = exports.levelsOf = exports.TENANT_TYPES = exports.TenantType = exports.AuthorizeDenyReason = exports.PermissionCategory = exports.PermissionScope = exports.bitsToPermissions = exports.permissionsToBits = exports.PERMS_VERSION = exports.PERMISSION_BIT_ORDER = exports.Permission = void 0;
27
27
  var Permission_1 = require("./enums/Permission");
28
28
  Object.defineProperty(exports, "Permission", { enumerable: true, get: function () { return Permission_1.Permission; } });
29
+ Object.defineProperty(exports, "PERMISSION_BIT_ORDER", { enumerable: true, get: function () { return Permission_1.PERMISSION_BIT_ORDER; } });
30
+ Object.defineProperty(exports, "PERMS_VERSION", { enumerable: true, get: function () { return Permission_1.PERMS_VERSION; } });
31
+ Object.defineProperty(exports, "permissionsToBits", { enumerable: true, get: function () { return Permission_1.permissionsToBits; } });
32
+ Object.defineProperty(exports, "bitsToPermissions", { enumerable: true, get: function () { return Permission_1.bitsToPermissions; } });
29
33
  var PermissionScope_1 = require("./enums/PermissionScope");
30
34
  Object.defineProperty(exports, "PermissionScope", { enumerable: true, get: function () { return PermissionScope_1.PermissionScope; } });
31
35
  var PermissionCategory_1 = require("./enums/PermissionCategory");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.70.0",
3
+ "version": "3.71.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -2,8 +2,11 @@ import { Expose } from 'class-transformer';
2
2
  import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
3
3
 
4
4
  export class CreateUserRequest {
5
- @Expose() @IsString() @IsNotEmpty() userPoolId!: string;
6
- @Expose() @IsString() @IsNotEmpty() region!: string;
5
+ // userPoolId + region son OPCIONALES: el alta de usuario PLATFORM ya no los manda desde el front
6
+ // (el backend platform-rbac-business los resuelve de la config del tenant 'platform'). Se conservan
7
+ // en el DTO porque los demás callers del connector SÍ los proveen.
8
+ @Expose() @IsOptional() @IsString() userPoolId?: string;
9
+ @Expose() @IsOptional() @IsString() region?: string;
7
10
  @Expose() @IsEmail() email!: string;
8
11
  @Expose() @IsOptional() @IsString() displayName?: string;
9
12
  @Expose() @IsString() @IsNotEmpty() tenantId!: string;
@@ -19,4 +19,10 @@ export interface AuthContext {
19
19
  permissions: Permission[];
20
20
  resolvedAt: string;
21
21
  issuer?: string;
22
+ /** Bitset base64url de permisos efectivos (token-as-cache). Ausente → fallback al resolver/claim. */
23
+ permBits?: string;
24
+ /** Versión del catálogo (PERMS_VERSION) con la que se construyó permBits. */
25
+ permVer?: number;
26
+ /** Epoch de permisos del tenant al momento de emitir el token. */
27
+ permsEpoch?: number;
22
28
  }
@@ -0,0 +1,9 @@
1
+ import type { Permission } from '../enums/Permission';
2
+ import type { RoleAssignmentInfo } from './RoleAssignmentInfo';
3
+
4
+ /** Respuesta de platform-rbac-business /internal/effective-permissions (consumida por jwt-inyector). */
5
+ export interface EffectivePermissionsResponse {
6
+ permissions: Permission[];
7
+ roleAssignments: RoleAssignmentInfo[];
8
+ permsEpoch: number;
9
+ }
@@ -137,3 +137,139 @@ export enum Permission {
137
137
  // ====================================================
138
138
  PAY_TRANSACTION_VIEW = 'pay.transaction.view',
139
139
  }
140
+
141
+ /**
142
+ * Orden CANÓNICO y APPEND-ONLY de los permisos para el bitset del token.
143
+ * Índice de cada permiso = su posición de bit. NUNCA reordenar ni borrar:
144
+ * deprecados CONSERVAN su posición; los nuevos van SIEMPRE al final.
145
+ * Derivado explícitamente (no Object.values, frágil ante edición del enum).
146
+ */
147
+ export const PERMISSION_BIT_ORDER: readonly Permission[] = [
148
+ Permission.RBAC_CATALOG_MANAGE,
149
+ Permission.PLATFORM_TENANT_CREATE,
150
+ Permission.PLATFORM_TENANT_LIST,
151
+ Permission.PLATFORM_TENANT_VIEW,
152
+ Permission.PLATFORM_TENANT_UPDATE,
153
+ Permission.PLATFORM_TENANT_SUSPEND,
154
+ Permission.PLATFORM_TENANT_ACTIVATE,
155
+ Permission.PLATFORM_TENANT_ADMIN_REPLACE,
156
+ Permission.PLATFORM_COGNITO_POOL_MANAGE,
157
+ Permission.PLATFORM_COGNITO_POOL_LIST,
158
+ Permission.PLATFORM_USER_CREATE,
159
+ Permission.PLATFORM_USER_LIST,
160
+ Permission.PLATFORM_USER_VIEW,
161
+ Permission.PLATFORM_USER_UPDATE,
162
+ Permission.PLATFORM_USER_DISABLE,
163
+ Permission.PLATFORM_USER_ENABLE,
164
+ Permission.PLATFORM_USER_DELETE,
165
+ Permission.PLATFORM_ROLE_CREATE,
166
+ Permission.PLATFORM_ROLE_LIST,
167
+ Permission.PLATFORM_ROLE_UPDATE,
168
+ Permission.PLATFORM_ROLE_DELETE,
169
+ Permission.PLATFORM_AUDIT_VIEW,
170
+ Permission.TENANT_USER_CREATE,
171
+ Permission.TENANT_USER_CREATE_LATERAL,
172
+ Permission.TENANT_USER_READ,
173
+ Permission.TENANT_USER_STATUS,
174
+ Permission.TENANT_USER_LIST,
175
+ Permission.TENANT_USER_VIEW,
176
+ Permission.TENANT_USER_UPDATE,
177
+ Permission.TENANT_USER_DISABLE,
178
+ Permission.TENANT_USER_ENABLE,
179
+ Permission.TENANT_USER_DELETE,
180
+ Permission.TENANT_USER_MFA_RESET,
181
+ Permission.TENANT_USER_PASSWORD_RESET,
182
+ Permission.TENANT_ROLE_CREATE,
183
+ Permission.TENANT_ROLE_LIST,
184
+ Permission.TENANT_ROLE_UPDATE,
185
+ Permission.TENANT_ROLE_DELETE,
186
+ Permission.TENANT_ROLE_VIEW,
187
+ Permission.TENANT_ROLE_ASSIGN,
188
+ Permission.TENANT_ROLE_REVOKE,
189
+ Permission.TENANT_SECURITY_POLICY_VIEW,
190
+ Permission.TENANT_SECURITY_POLICY_MANAGE,
191
+ Permission.TENANT_BRANDING_MANAGE,
192
+ Permission.TENANT_AUDIT_VIEW,
193
+ Permission.RETAIL_USER_CREATE,
194
+ Permission.RETAIL_USER_CREATE_LATERAL,
195
+ Permission.RETAIL_USER_READ,
196
+ Permission.RETAIL_USER_UPDATE,
197
+ Permission.RETAIL_USER_STATUS,
198
+ Permission.RETAIL_USER_DELETE,
199
+ Permission.RETAIL_USER_PASSWORD_RESET,
200
+ Permission.RETAIL_USER_MFA_RESET,
201
+ Permission.RETAIL_PRODUCT_CREATE,
202
+ Permission.RETAIL_PRODUCT_LIST,
203
+ Permission.RETAIL_PRODUCT_VIEW,
204
+ Permission.RETAIL_PRODUCT_UPDATE,
205
+ Permission.RETAIL_PRODUCT_DELETE,
206
+ Permission.RETAIL_PRODUCT_MDM_CONFIG,
207
+ Permission.RETAIL_INVENTORY_LIST,
208
+ Permission.RETAIL_INVENTORY_VIEW,
209
+ Permission.RETAIL_INVENTORY_UPDATE,
210
+ Permission.RETAIL_SALE_CREATE,
211
+ Permission.RETAIL_SALE_LIST,
212
+ Permission.RETAIL_SALE_CANCEL,
213
+ Permission.RETAIL_STORE_MANAGE,
214
+ Permission.RETAIL_RETAILER_MANAGE,
215
+ Permission.LEND_CREDIT_CREATE,
216
+ Permission.LEND_CREDIT_LIST,
217
+ Permission.LEND_CREDIT_VIEW,
218
+ Permission.LEND_CREDIT_UPDATE,
219
+ Permission.LEND_CREDIT_LIQUIDATE,
220
+ Permission.LEND_CREDIT_RESTRUCTURE,
221
+ Permission.LEND_PAYMENT_APPLY,
222
+ Permission.LEND_PAYMENT_LIST,
223
+ Permission.LEND_PAYMENT_REVERSE,
224
+ Permission.LEND_INSTALLMENT_VIEW,
225
+ Permission.MDM_DEVICE_ENROLL,
226
+ Permission.MDM_DEVICE_RELEASE,
227
+ Permission.MDM_DEVICE_ARCHIVE,
228
+ Permission.MDM_DEVICE_DEACTIVATE,
229
+ Permission.MDM_DEVICE_LOCK_MANUAL,
230
+ Permission.MDM_DEVICE_UNLOCK_MANUAL,
231
+ Permission.MDM_DEVICE_PIN_UNLOCK,
232
+ Permission.MDM_DEVICE_EXTEND_VALIDITY,
233
+ Permission.MDM_DEVICE_NOTIFY,
234
+ Permission.MDM_DEVICE_STATUS_VIEW,
235
+ Permission.MDM_OPERATION_LOG_VIEW,
236
+ Permission.MDM_TEST,
237
+ Permission.PAY_TRANSACTION_VIEW,
238
+ ] as const;
239
+
240
+ function djb2(input: string): number {
241
+ let h = 5381;
242
+ for (let i = 0; i < input.length; i++) h = ((h << 5) + h + input.charCodeAt(i)) >>> 0;
243
+ return h;
244
+ }
245
+ /** Versión del catálogo = hash del orden. Cambia solo si el orden cambia. */
246
+ export const PERMS_VERSION: number = djb2(PERMISSION_BIT_ORDER.join('|'));
247
+
248
+ const BIT_INDEX: ReadonlyMap<Permission, number> = new Map(PERMISSION_BIT_ORDER.map((p, i) => [p, i]));
249
+
250
+ /** Comprime un set de permisos a bitset base64url. */
251
+ export function permissionsToBits(perms: readonly Permission[]): string {
252
+ const bytes = new Uint8Array(Math.ceil(PERMISSION_BIT_ORDER.length / 8));
253
+ for (const p of perms) {
254
+ const idx = BIT_INDEX.get(p);
255
+ if (idx === undefined) continue;
256
+ bytes[idx >> 3] |= 1 << (idx & 7);
257
+ }
258
+ return Buffer.from(bytes).toString('base64url');
259
+ }
260
+ /** Decodifica un bitset base64url a la lista de permisos. Tolerante a basura → []. */
261
+ export function bitsToPermissions(bits: string): Permission[] {
262
+ if (typeof bits !== 'string' || bits.length === 0) return [];
263
+ let bytes: Buffer;
264
+ try {
265
+ bytes = Buffer.from(bits, 'base64url');
266
+ } catch {
267
+ return [];
268
+ }
269
+ const out: Permission[] = [];
270
+ for (let i = 0; i < PERMISSION_BIT_ORDER.length; i++) {
271
+ const byte = bytes[i >> 3] ?? 0;
272
+ if (byte & (1 << (i & 7))) out.push(PERMISSION_BIT_ORDER[i]);
273
+ }
274
+ return out;
275
+ }
@@ -4,17 +4,24 @@
4
4
  // del platform-rbac-business documenta la migración futura de los 4 símbolos cross-cutting
5
5
  // (Permission, PermissionScope, AuthContext, RoleAssignmentInfo) de aquí a `rbac/`.
6
6
  //
7
- // En Fase 1.A los DTOs propios del rbac-business (CreateTenantRequest, AssignRoleRequest,
8
- // EffectivePermissionsResponse, etc.) NO viven en este módulo todavía — se agregan en
9
- // Fase 1.B cuando los managers que los consumen se implementen.
7
+ // Los DTOs propios del rbac-business se van agregando a medida que los flujos los necesitan.
8
+ // EffectivePermissionsResponse ya vive acá (lo consume jwt-inyector vía /internal/effective-permissions).
9
+ // Otros DTOs aún pendientes se sumarán cuando los managers que los consumen se implementen.
10
10
 
11
- export { Permission } from './enums/Permission';
11
+ export {
12
+ Permission,
13
+ PERMISSION_BIT_ORDER,
14
+ PERMS_VERSION,
15
+ permissionsToBits,
16
+ bitsToPermissions,
17
+ } from './enums/Permission';
12
18
  export { PermissionScope } from './enums/PermissionScope';
13
19
  export { PermissionCategory } from './enums/PermissionCategory';
14
20
 
15
21
  export type { AuthContext } from './dtos/AuthContext';
16
22
  export type { RoleAssignmentInfo } from './dtos/RoleAssignmentInfo';
17
23
  export type { PermissionMeta } from './dtos/PermissionMeta';
24
+ export type { EffectivePermissionsResponse } from './dtos/EffectivePermissionsResponse';
18
25
 
19
26
  // Fase 1 — Custom Auth Challenge (Email OTP + TOTP) + MFA self-service.
20
27
  // Class values (no type-only) — los DTOs llevan decoradores class-validator y se hidratan con plainToInstance en runtime.