@fiado/api-invoker 5.86.0 → 5.87.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.
@@ -1,6 +1,6 @@
1
1
  import type { IHttpRequest } from "@fiado/http-client";
2
- import { ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
3
- import { DefineNextChallengeRequest, DefineNextChallengeResponse, PrepareChallengeRequest, PrepareChallengeResponse, VerifyChallengeRequest, VerifyChallengeResponse, AuthorizeRequest, AuthorizeResponse, EffectivePermissionsResponse, InjectableUserAttributesResponse, PermissionScope, CreateLevelEntityRequest, CreateLevelEntityResponse, CreateTenantUserRequest, CreateTenantUserResponse, UserProfileResponse } from "@fiado/type-kit/bin/platformRbac/index.js";
2
+ import { APIGatewayProxyResultBody, ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
3
+ import { DefineNextChallengeRequest, DefineNextChallengeResponse, PrepareChallengeRequest, PrepareChallengeResponse, VerifyChallengeRequest, VerifyChallengeResponse, AuthorizeRequest, AuthorizeResponse, EffectivePermissionsResponse, InjectableUserAttributesResponse, PermissionScope, CreateLevelEntityRequest, CreateLevelEntityResponse, CreateTenantUserRequest, CreateTenantUserResponse, UserProfileResponse, ListLevelEntitiesResponse, LevelEntityResponse, UpdateLevelEntityRequest, DeleteLevelEntityRequest, DeleteLevelEntityResponse, ListTenantUsersResponse, GetTenantUserResponse, TenantUserResponse, TenantUserAckResponse, UpdateTenantUserRequest, DeleteTenantUserRequest, DisableTenantUserRequest, EnableTenantUserRequest, ResetTenantUserPasswordRequest, ResetTenantUserPasswordResponse, ResetTenantUserMfaRequest, ListTenantRolesResponse, AssignTenantRoleRequest, AssignTenantRoleResponse, RevokeTenantRoleRequest, RevokeTenantRoleResponse } from "@fiado/type-kit/bin/platformRbac/index.js";
4
4
  import { IPlatformRbacBusinessApi } from "./interfaces/IPlatformRbacBusinessApi.js";
5
5
  /**
6
6
  * Publisher HTTP del lambda `platform-rbac-business` (componente 06 SureKeep Fase 0)
@@ -29,4 +29,51 @@ export default class PlatformRbacBusinessApi implements IPlatformRbacBusinessApi
29
29
  createLevelEntity(tenantId: string, level: PermissionScope, input: CreateLevelEntityRequest): Promise<ApiGatewayResponse<CreateLevelEntityResponse>>;
30
30
  createTenantUser(tenantId: string, input: CreateTenantUserRequest): Promise<ApiGatewayResponse<CreateTenantUserResponse>>;
31
31
  getUserProfile(cognitoSub: string, tenantId: string): Promise<ApiGatewayResponse<UserProfileResponse>>;
32
+ /** Ruta base de los grupos (entidades de nivel) de un tenant. */
33
+ private _levelEntitiesUrl;
34
+ /** Ruta base de los usuarios de un tenant. */
35
+ private _tenantUsersUrl;
36
+ private _deleteWithBody;
37
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities — lista los grupos de un nivel; `parentId` filtra por los hijos de un grupo. */
38
+ listLevelEntities(tenantId: string, level: PermissionScope, parentId?: string): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>>;
39
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
40
+ getLevelEntity(tenantId: string, level: PermissionScope, id: string): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
41
+ /** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo. */
42
+ updateLevelEntity(tenantId: string, level: PermissionScope, id: string, input: UpdateLevelEntityRequest): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
43
+ /** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
44
+ deleteLevelEntity(tenantId: string, level: PermissionScope, id: string, input: DeleteLevelEntityRequest): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>>;
45
+ /**
46
+ * GET /internal/tenants/{tenantId}/users — lista los usuarios del tenant.
47
+ * El filtro `email` es lo que permite adoptar una cuenta que ya existía.
48
+ */
49
+ listTenantUsers(tenantId: string, email?: string): Promise<APIGatewayProxyResultBody<ListTenantUsersResponse>>;
50
+ /**
51
+ * GET /internal/tenants/{tenantId}/users/{cognitoSub} — detalle de un usuario.
52
+ * De aquí sale el `assignmentId` que hace falta para revocar un rol.
53
+ */
54
+ getTenantUser(tenantId: string, cognitoSub: string): Promise<APIGatewayProxyResultBody<GetTenantUserResponse>>;
55
+ /** PUT /internal/tenants/{tenantId}/users/{cognitoSub} — renombra a un usuario. */
56
+ updateTenantUser(tenantId: string, cognitoSub: string, input: UpdateTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserResponse>>;
57
+ /** DELETE /internal/tenants/{tenantId}/users/{cognitoSub} — borra a un usuario. El `actedBy` viaja en el cuerpo. */
58
+ deleteTenantUser(tenantId: string, cognitoSub: string, input: DeleteTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
59
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/disable — suspende a un usuario. */
60
+ disableTenantUser(tenantId: string, cognitoSub: string, input: DisableTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
61
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/enable — reactiva a un usuario suspendido. */
62
+ enableTenantUser(tenantId: string, cognitoSub: string, input: EnableTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
63
+ /**
64
+ * POST /internal/tenants/{tenantId}/users/{cognitoSub}/password-reset — resetea la contraseña.
65
+ * Devuelve la contraseña temporal en claro; no se manda correo.
66
+ */
67
+ resetTenantUserPassword(tenantId: string, cognitoSub: string, input: ResetTenantUserPasswordRequest): Promise<APIGatewayProxyResultBody<ResetTenantUserPasswordResponse>>;
68
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/mfa-reset — resetea el MFA de un usuario. */
69
+ resetTenantUserMfa(tenantId: string, cognitoSub: string, input: ResetTenantUserMfaRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
70
+ /** GET /internal/tenants/{tenantId}/roles — catálogo de roles del tenant, para armar el selector de asignación. */
71
+ listTenantRoles(tenantId: string): Promise<APIGatewayProxyResultBody<ListTenantRolesResponse>>;
72
+ /** POST /internal/tenants/{tenantId}/role-assignments — asigna un rol a un usuario en un scope. */
73
+ assignTenantRole(tenantId: string, input: AssignTenantRoleRequest): Promise<APIGatewayProxyResultBody<AssignTenantRoleResponse>>;
74
+ /**
75
+ * POST /internal/tenants/{tenantId}/role-assignments/{assignmentId}/revoke — revoca una asignación.
76
+ * El `cognitoSub` va en el cuerpo porque es parte de la llave de la tabla de asignaciones.
77
+ */
78
+ revokeTenantRole(tenantId: string, assignmentId: string, input: RevokeTenantRoleRequest): Promise<APIGatewayProxyResultBody<RevokeTenantRoleResponse>>;
32
79
  }
@@ -80,6 +80,111 @@ let PlatformRbacBusinessApi = class PlatformRbacBusinessApi {
80
80
  const url = `${this.baseUrl}/internal/users/${encodeURIComponent(cognitoSub)}/profile?tenantId=${encodeURIComponent(tenantId)}`;
81
81
  return await this.httpRequest.get(url);
82
82
  }
83
+ // ── Administración de RBAC para el hub de agentes (grupos, usuarios y roles) ──
84
+ // Tipados `APIGatewayProxyResultBody<T>`, el shape REAL que devuelve @fiado/http-client:
85
+ // el body HTTP crudo `{ code, date, msg, data }`, con el payload en `.data` (TD-AI-003).
86
+ /** Ruta base de los grupos (entidades de nivel) de un tenant. */
87
+ _levelEntitiesUrl(tenantId, level) {
88
+ return `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/levels/${encodeURIComponent(level)}/entities`;
89
+ }
90
+ /** Ruta base de los usuarios de un tenant. */
91
+ _tenantUsersUrl(tenantId) {
92
+ return `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/users`;
93
+ }
94
+ // `IHttpRequest.delete` manda su segundo argumento como QUERY STRING, no como cuerpo: el cuerpo
95
+ // solo llega por `extraConfig` ({ data }). `actedBy` va ahí para no quedar en los logs de API Gateway.
96
+ async _deleteWithBody(url, body) {
97
+ return await this.httpRequest.delete(url, undefined, undefined, undefined, undefined, { data: body });
98
+ }
99
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities — lista los grupos de un nivel; `parentId` filtra por los hijos de un grupo. */
100
+ async listLevelEntities(tenantId, level, parentId) {
101
+ const base = this._levelEntitiesUrl(tenantId, level);
102
+ const url = parentId ? `${base}?parentId=${encodeURIComponent(parentId)}` : base;
103
+ return await this.httpRequest.get(url);
104
+ }
105
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
106
+ async getLevelEntity(tenantId, level, id) {
107
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
108
+ return await this.httpRequest.get(url);
109
+ }
110
+ /** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo. */
111
+ async updateLevelEntity(tenantId, level, id, input) {
112
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
113
+ return await this.httpRequest.put(url, input);
114
+ }
115
+ /** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
116
+ async deleteLevelEntity(tenantId, level, id, input) {
117
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
118
+ return await this._deleteWithBody(url, input);
119
+ }
120
+ /**
121
+ * GET /internal/tenants/{tenantId}/users — lista los usuarios del tenant.
122
+ * El filtro `email` es lo que permite adoptar una cuenta que ya existía.
123
+ */
124
+ async listTenantUsers(tenantId, email) {
125
+ const base = this._tenantUsersUrl(tenantId);
126
+ const url = email ? `${base}?email=${encodeURIComponent(email)}` : base;
127
+ return await this.httpRequest.get(url);
128
+ }
129
+ /**
130
+ * GET /internal/tenants/{tenantId}/users/{cognitoSub} — detalle de un usuario.
131
+ * De aquí sale el `assignmentId` que hace falta para revocar un rol.
132
+ */
133
+ async getTenantUser(tenantId, cognitoSub) {
134
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
135
+ return await this.httpRequest.get(url);
136
+ }
137
+ /** PUT /internal/tenants/{tenantId}/users/{cognitoSub} — renombra a un usuario. */
138
+ async updateTenantUser(tenantId, cognitoSub, input) {
139
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
140
+ return await this.httpRequest.put(url, input);
141
+ }
142
+ /** DELETE /internal/tenants/{tenantId}/users/{cognitoSub} — borra a un usuario. El `actedBy` viaja en el cuerpo. */
143
+ async deleteTenantUser(tenantId, cognitoSub, input) {
144
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
145
+ return await this._deleteWithBody(url, input);
146
+ }
147
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/disable — suspende a un usuario. */
148
+ async disableTenantUser(tenantId, cognitoSub, input) {
149
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/disable`;
150
+ return await this.httpRequest.post(url, input);
151
+ }
152
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/enable — reactiva a un usuario suspendido. */
153
+ async enableTenantUser(tenantId, cognitoSub, input) {
154
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/enable`;
155
+ return await this.httpRequest.post(url, input);
156
+ }
157
+ /**
158
+ * POST /internal/tenants/{tenantId}/users/{cognitoSub}/password-reset — resetea la contraseña.
159
+ * Devuelve la contraseña temporal en claro; no se manda correo.
160
+ */
161
+ async resetTenantUserPassword(tenantId, cognitoSub, input) {
162
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/password-reset`;
163
+ return await this.httpRequest.post(url, input);
164
+ }
165
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/mfa-reset — resetea el MFA de un usuario. */
166
+ async resetTenantUserMfa(tenantId, cognitoSub, input) {
167
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/mfa-reset`;
168
+ return await this.httpRequest.post(url, input);
169
+ }
170
+ /** GET /internal/tenants/{tenantId}/roles — catálogo de roles del tenant, para armar el selector de asignación. */
171
+ async listTenantRoles(tenantId) {
172
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/roles`;
173
+ return await this.httpRequest.get(url);
174
+ }
175
+ /** POST /internal/tenants/{tenantId}/role-assignments — asigna un rol a un usuario en un scope. */
176
+ async assignTenantRole(tenantId, input) {
177
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/role-assignments`;
178
+ return await this.httpRequest.post(url, input);
179
+ }
180
+ /**
181
+ * POST /internal/tenants/{tenantId}/role-assignments/{assignmentId}/revoke — revoca una asignación.
182
+ * El `cognitoSub` va en el cuerpo porque es parte de la llave de la tabla de asignaciones.
183
+ */
184
+ async revokeTenantRole(tenantId, assignmentId, input) {
185
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/role-assignments/${encodeURIComponent(assignmentId)}/revoke`;
186
+ return await this.httpRequest.post(url, input);
187
+ }
83
188
  };
84
189
  PlatformRbacBusinessApi = __decorate([
85
190
  injectable(),
@@ -1,5 +1,5 @@
1
- import { ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
2
- import { DefineNextChallengeRequest, DefineNextChallengeResponse, PrepareChallengeRequest, PrepareChallengeResponse, VerifyChallengeRequest, VerifyChallengeResponse, AuthorizeRequest, AuthorizeResponse, EffectivePermissionsResponse, InjectableUserAttributesResponse, PermissionScope, CreateLevelEntityRequest, CreateLevelEntityResponse, CreateTenantUserRequest, CreateTenantUserResponse, UserProfileResponse } from "@fiado/type-kit/bin/platformRbac/index.js";
1
+ import { APIGatewayProxyResultBody, ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
2
+ import { DefineNextChallengeRequest, DefineNextChallengeResponse, PrepareChallengeRequest, PrepareChallengeResponse, VerifyChallengeRequest, VerifyChallengeResponse, AuthorizeRequest, AuthorizeResponse, EffectivePermissionsResponse, InjectableUserAttributesResponse, PermissionScope, CreateLevelEntityRequest, CreateLevelEntityResponse, CreateTenantUserRequest, CreateTenantUserResponse, UserProfileResponse, ListLevelEntitiesResponse, LevelEntityResponse, UpdateLevelEntityRequest, DeleteLevelEntityRequest, DeleteLevelEntityResponse, ListTenantUsersResponse, GetTenantUserResponse, TenantUserResponse, TenantUserAckResponse, UpdateTenantUserRequest, DeleteTenantUserRequest, DisableTenantUserRequest, EnableTenantUserRequest, ResetTenantUserPasswordRequest, ResetTenantUserPasswordResponse, ResetTenantUserMfaRequest, ListTenantRolesResponse, AssignTenantRoleRequest, AssignTenantRoleResponse, RevokeTenantRoleRequest, RevokeTenantRoleResponse } from "@fiado/type-kit/bin/platformRbac/index.js";
3
3
  /**
4
4
  * Contrato del publisher HTTP del lambda `platform-rbac-business` (componente 06 SureKeep Fase 0)
5
5
  * para los 3 endpoints internos del Custom Auth Challenge flow (MFA).
@@ -8,8 +8,8 @@ import { DefineNextChallengeRequest, DefineNextChallengeResponse, PrepareChallen
8
8
  * `defineAuthChallenge`, `createAuthChallenge` y `verifyAuthChallengeResponse`
9
9
  * configurados en cada User Pool aprovisionado por la saga `TenantOnboardingManager`.
10
10
  *
11
- * Patrón de retorno: `Promise<ApiGatewayResponse<T>>` sin unwrap (v4 canonical Fiado).
12
- * El consumer accede `result.body.data` para llegar al payload tipado.
11
+ * Devuelve el body HTTP crudo `{ code, date, msg, data }`, con el payload en `.data`: el tipo honesto es
12
+ * el de los métodos de administración. Los `ApiGatewayResponse<T>` mienten y quedan por TD-AI-003.
13
13
  *
14
14
  * Env var requerida en el consumer: `PLATFORM_RBAC_BUSINESS_URL`.
15
15
  * El template.yml del consumer la setea con:
@@ -77,4 +77,47 @@ export interface IPlatformRbacBusinessApi {
77
77
  createTenantUser(tenantId: string, input: CreateTenantUserRequest): Promise<ApiGatewayResponse<CreateTenantUserResponse>>;
78
78
  /** GET /internal/users/{cognitoSub}/profile?tenantId= — perfil básico del SharedUser (displayName, email, phone, status). */
79
79
  getUserProfile(cognitoSub: string, tenantId: string): Promise<ApiGatewayResponse<UserProfileResponse>>;
80
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities — lista los grupos de un nivel; `parentId` filtra por los hijos de un grupo. */
81
+ listLevelEntities(tenantId: string, level: PermissionScope, parentId?: string): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>>;
82
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
83
+ getLevelEntity(tenantId: string, level: PermissionScope, id: string): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
84
+ /** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo. */
85
+ updateLevelEntity(tenantId: string, level: PermissionScope, id: string, input: UpdateLevelEntityRequest): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
86
+ /** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
87
+ deleteLevelEntity(tenantId: string, level: PermissionScope, id: string, input: DeleteLevelEntityRequest): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>>;
88
+ /**
89
+ * GET /internal/tenants/{tenantId}/users — lista los usuarios del tenant.
90
+ * El filtro `email` es lo que permite adoptar una cuenta que ya existía: antes de crear un
91
+ * usuario se pregunta si ese correo ya tiene uno.
92
+ */
93
+ listTenantUsers(tenantId: string, email?: string): Promise<APIGatewayProxyResultBody<ListTenantUsersResponse>>;
94
+ /**
95
+ * GET /internal/tenants/{tenantId}/users/{cognitoSub} — detalle de un usuario.
96
+ * De aquí sale el `assignmentId` que hace falta para revocar un rol.
97
+ */
98
+ getTenantUser(tenantId: string, cognitoSub: string): Promise<APIGatewayProxyResultBody<GetTenantUserResponse>>;
99
+ /** PUT /internal/tenants/{tenantId}/users/{cognitoSub} — renombra a un usuario. */
100
+ updateTenantUser(tenantId: string, cognitoSub: string, input: UpdateTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserResponse>>;
101
+ /** DELETE /internal/tenants/{tenantId}/users/{cognitoSub} — borra a un usuario. El `actedBy` viaja en el cuerpo. */
102
+ deleteTenantUser(tenantId: string, cognitoSub: string, input: DeleteTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
103
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/disable — suspende a un usuario. */
104
+ disableTenantUser(tenantId: string, cognitoSub: string, input: DisableTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
105
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/enable — reactiva a un usuario suspendido. */
106
+ enableTenantUser(tenantId: string, cognitoSub: string, input: EnableTenantUserRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
107
+ /**
108
+ * POST /internal/tenants/{tenantId}/users/{cognitoSub}/password-reset — resetea la contraseña.
109
+ * Devuelve la contraseña temporal en claro; no se manda correo.
110
+ */
111
+ resetTenantUserPassword(tenantId: string, cognitoSub: string, input: ResetTenantUserPasswordRequest): Promise<APIGatewayProxyResultBody<ResetTenantUserPasswordResponse>>;
112
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/mfa-reset — resetea el MFA de un usuario. */
113
+ resetTenantUserMfa(tenantId: string, cognitoSub: string, input: ResetTenantUserMfaRequest): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
114
+ /** GET /internal/tenants/{tenantId}/roles — catálogo de roles del tenant, para armar el selector de asignación. */
115
+ listTenantRoles(tenantId: string): Promise<APIGatewayProxyResultBody<ListTenantRolesResponse>>;
116
+ /** POST /internal/tenants/{tenantId}/role-assignments — asigna un rol a un usuario en un scope. */
117
+ assignTenantRole(tenantId: string, input: AssignTenantRoleRequest): Promise<APIGatewayProxyResultBody<AssignTenantRoleResponse>>;
118
+ /**
119
+ * POST /internal/tenants/{tenantId}/role-assignments/{assignmentId}/revoke — revoca una asignación.
120
+ * El `cognitoSub` va en el cuerpo porque es parte de la llave de la tabla de asignaciones.
121
+ */
122
+ revokeTenantRole(tenantId: string, assignmentId: string, input: RevokeTenantRoleRequest): Promise<APIGatewayProxyResultBody<RevokeTenantRoleResponse>>;
80
123
  }
package/docs/TECH_DEBT.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  Registro vivo de deudas conscientes del repo. Cada entrada con ID estable `TD-AI-NNN` y los 4 campos canónicos (contexto / asunción / condición para cerrar / bloqueante).
4
4
 
5
- ## TD-AI-001 — 2026-05-29 — npm link @fiado/type-kit activo
5
+ ## TD-AI-001 — 2026-05-29 — CERRADA 2026-09-21 — npm link @fiado/type-kit activo
6
+
7
+ - **Cierre:** el symlink se quitó y se reinstaló `@fiado/type-kit@3.455.0` desde el registry. `tsc --noEmit` en cero y 331 tests en verde, así que el módulo `platformRbac` ya resuelve sin link. El detalle de abajo es histórico.
6
8
 
7
9
  - **Contexto:** `node_modules/@fiado/type-kit` es symlink local a `C:/Users/Fiado/Documents/Repos/fiado-type-kit/` (v3.43.1) — el publicado en CodeArtifact es v3.42.0 sin el módulo `platformRbac` que el Publisher `PlatformRbacBusinessApi` nuevo (`src/platformRbac/`) importa. El link se activó para iterar localmente sin publish prematuro del type-kit (decisión del user en el plan `2026-05-29-custom-auth-challenge-mfa.md`).
8
10
  - **Asunción / pendiente:** el `npm run build` y `tsc --noEmit` funcionan con el link, pero CI y cualquier `npm install` fresh van a resolver desde CodeArtifact (3.42.0) y fallar con `TS2307: Cannot find module '@fiado/type-kit/bin/platformRbac'` en los 2 archivos nuevos del Publisher.
@@ -21,3 +23,17 @@ Registro vivo de deudas conscientes del repo. Cada entrada con ID estable `TD-AI
21
23
  - **Asunción / pendiente:** se tiparon inline a propósito para no bloquear el cableado del wizard F2 en un bump de type-kit (regla de la sesión: NO tocar type-kit sin OK). Los shapes espejan fielmente el contrato del destino verificado en código.
22
24
  - **Condición para cerrar:** cuando `retail-catalog-business`/`retail-cards-business` publiquen esos DTOs en `@fiado/type-kit` (dominios `retailCatalog`/`retailCards`), reemplazar los inline por el import del type-kit y bumpear.
23
25
  - **Bloqueante:** NO — el contrato de red es correcto; es unificación de tipos con downstream.
26
+
27
+ ## TD-AI-003 — 2026-09-21 — el tipo de retorno de los publishers miente sobre el shape real
28
+
29
+ - **Contexto:** `@fiado/http-client` hace `return response.data` de axios, así que lo que llega en runtime es el body HTTP crudo del `ApiResponse` del lambda destino: `{ code, date, msg, data }`, con el payload en `.data`. Los 43 archivos de `src/` que declaran `Promise<ApiGatewayResponse<T>>` (`{ statusCode, body }`) declaran un shape que nunca existe. Ya costó un crash: leer `.body` en `ApiInvokerPermissionResolver` daba `undefined` y reventaba `enforceRbac`, y `retail-org-business` compensa con `response as unknown as Record<string, unknown>` + `(raw?.data ?? raw)` al consumir `createLevelEntity`.
30
+ - **Asunción / pendiente:** los 15 métodos de administración de RBAC (`listLevelEntities`..`revokeTenantRole`) ya se tipan `APIGatewayProxyResultBody<T>` de `@fiado/gateway-adapter`, que es el shape honesto — mismo precedente que `CollectorApi.getCollectorTransactionByIds`. Los métodos viejos NO se tocaron: corregirlos por abajo rompe la compensación de los consumidores vivos que ya leen `?? raw`.
31
+ - **Condición para cerrar:** migrar los 43 archivos a `APIGatewayProxyResultBody<T>` en un bump coordinado, quitando en el mismo movimiento los casts de compensación de cada consumer (arrancando por `retail-org-business`). No es de este ciclo.
32
+ - **Bloqueante:** NO — el contrato de red es correcto y el shape honesto ya es el de los métodos nuevos; es unificación de tipos.
33
+
34
+ ## TD-AI-004 — 2026-09-21 — CERRADA — npm link @fiado/type-kit (DTOs de administración de RBAC)
35
+
36
+ - **Contexto:** durante el desarrollo, `node_modules/@fiado/type-kit` fue symlink al repo local porque los 15 métodos de administración de RBAC importaban DTOs que la versión publicada todavía no tenía.
37
+ - **Cómo se cerró:** publicada `@fiado/type-kit@3.455.0`, se quitó el symlink y se reinstaló desde el registry. `tsc --noEmit` en cero y 331 tests en verde contra el árbol del registry.
38
+ - **Lo que el link tapaba, y conviene recordar:** `tsc` no limpia `bin/`, así que artefactos compilados de DTOs ya borrados seguían resolviendo a través del symlink. Un `npm link` puede hacer compilar contra tipos que ya no existen.
39
+ - **Trampa del teardown:** `npm unlink <pkg>` en npm 7+ es alias de `uninstall` y BORRA la dependencia de `package.json`. Hay que restaurarla antes del `npm install`, o el paquete se resuelve como transitiva en una versión vieja.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/api-invoker",
3
- "version": "5.86.0",
3
+ "version": "5.87.0",
4
4
  "description": "Sirve como un puente entre diferentes funciones lambda, facilitando la comunicación entre ellas a través de invocaciones http",
5
5
  "type": "module",
6
6
  "main": "bin/index.js",
@@ -1,7 +1,12 @@
1
1
  import { inject, injectable } from "inversify";
2
2
  import type { IHttpRequest } from "@fiado/http-client";
3
- import { ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
4
- // TD-AI-001: import de @fiado/type-kit/bin/platformRbac requiere npm link a type-kit 3.43.1 hasta publish final. Ver docs/TECH_DEBT.md.
3
+ import {
4
+ APIGatewayProxyResultBody,
5
+ ApiGatewayResponse,
6
+ ResolvedPermissions,
7
+ ResolveInput,
8
+ } from "@fiado/gateway-adapter";
9
+ // TD-AI-003: el tipo de retorno de los métodos viejos no refleja el runtime. Ver docs/TECH_DEBT.md.
5
10
  import {
6
11
  DefineNextChallengeRequest,
7
12
  DefineNextChallengeResponse,
@@ -19,6 +24,27 @@ import {
19
24
  CreateTenantUserRequest,
20
25
  CreateTenantUserResponse,
21
26
  UserProfileResponse,
27
+ ListLevelEntitiesResponse,
28
+ LevelEntityResponse,
29
+ UpdateLevelEntityRequest,
30
+ DeleteLevelEntityRequest,
31
+ DeleteLevelEntityResponse,
32
+ ListTenantUsersResponse,
33
+ GetTenantUserResponse,
34
+ TenantUserResponse,
35
+ TenantUserAckResponse,
36
+ UpdateTenantUserRequest,
37
+ DeleteTenantUserRequest,
38
+ DisableTenantUserRequest,
39
+ EnableTenantUserRequest,
40
+ ResetTenantUserPasswordRequest,
41
+ ResetTenantUserPasswordResponse,
42
+ ResetTenantUserMfaRequest,
43
+ ListTenantRolesResponse,
44
+ AssignTenantRoleRequest,
45
+ AssignTenantRoleResponse,
46
+ RevokeTenantRoleRequest,
47
+ RevokeTenantRoleResponse,
22
48
  } from "@fiado/type-kit/bin/platformRbac/index.js";
23
49
  import { IPlatformRbacBusinessApi } from "./interfaces/IPlatformRbacBusinessApi.js";
24
50
 
@@ -126,4 +152,185 @@ export default class PlatformRbacBusinessApi implements IPlatformRbacBusinessApi
126
152
  const url = `${this.baseUrl}/internal/users/${encodeURIComponent(cognitoSub)}/profile?tenantId=${encodeURIComponent(tenantId)}`;
127
153
  return await this.httpRequest.get(url);
128
154
  }
155
+
156
+ // ── Administración de RBAC para el hub de agentes (grupos, usuarios y roles) ──
157
+ // Tipados `APIGatewayProxyResultBody<T>`, el shape REAL que devuelve @fiado/http-client:
158
+ // el body HTTP crudo `{ code, date, msg, data }`, con el payload en `.data` (TD-AI-003).
159
+
160
+ /** Ruta base de los grupos (entidades de nivel) de un tenant. */
161
+ private _levelEntitiesUrl(tenantId: string, level: PermissionScope): string {
162
+ return `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/levels/${encodeURIComponent(level)}/entities`;
163
+ }
164
+
165
+ /** Ruta base de los usuarios de un tenant. */
166
+ private _tenantUsersUrl(tenantId: string): string {
167
+ return `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/users`;
168
+ }
169
+
170
+ // `IHttpRequest.delete` manda su segundo argumento como QUERY STRING, no como cuerpo: el cuerpo
171
+ // solo llega por `extraConfig` ({ data }). `actedBy` va ahí para no quedar en los logs de API Gateway.
172
+ private async _deleteWithBody<T>(url: string, body: unknown): Promise<T> {
173
+ return await this.httpRequest.delete<T>(url, undefined, undefined, undefined, undefined, { data: body });
174
+ }
175
+
176
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities — lista los grupos de un nivel; `parentId` filtra por los hijos de un grupo. */
177
+ async listLevelEntities(
178
+ tenantId: string,
179
+ level: PermissionScope,
180
+ parentId?: string,
181
+ ): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>> {
182
+ const base = this._levelEntitiesUrl(tenantId, level);
183
+ const url = parentId ? `${base}?parentId=${encodeURIComponent(parentId)}` : base;
184
+ return await this.httpRequest.get(url);
185
+ }
186
+
187
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
188
+ async getLevelEntity(
189
+ tenantId: string,
190
+ level: PermissionScope,
191
+ id: string,
192
+ ): Promise<APIGatewayProxyResultBody<LevelEntityResponse>> {
193
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
194
+ return await this.httpRequest.get(url);
195
+ }
196
+
197
+ /** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo. */
198
+ async updateLevelEntity(
199
+ tenantId: string,
200
+ level: PermissionScope,
201
+ id: string,
202
+ input: UpdateLevelEntityRequest,
203
+ ): Promise<APIGatewayProxyResultBody<LevelEntityResponse>> {
204
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
205
+ return await this.httpRequest.put(url, input);
206
+ }
207
+
208
+ /** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
209
+ async deleteLevelEntity(
210
+ tenantId: string,
211
+ level: PermissionScope,
212
+ id: string,
213
+ input: DeleteLevelEntityRequest,
214
+ ): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>> {
215
+ const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
216
+ return await this._deleteWithBody(url, input);
217
+ }
218
+
219
+ /**
220
+ * GET /internal/tenants/{tenantId}/users — lista los usuarios del tenant.
221
+ * El filtro `email` es lo que permite adoptar una cuenta que ya existía.
222
+ */
223
+ async listTenantUsers(
224
+ tenantId: string,
225
+ email?: string,
226
+ ): Promise<APIGatewayProxyResultBody<ListTenantUsersResponse>> {
227
+ const base = this._tenantUsersUrl(tenantId);
228
+ const url = email ? `${base}?email=${encodeURIComponent(email)}` : base;
229
+ return await this.httpRequest.get(url);
230
+ }
231
+
232
+ /**
233
+ * GET /internal/tenants/{tenantId}/users/{cognitoSub} — detalle de un usuario.
234
+ * De aquí sale el `assignmentId` que hace falta para revocar un rol.
235
+ */
236
+ async getTenantUser(
237
+ tenantId: string,
238
+ cognitoSub: string,
239
+ ): Promise<APIGatewayProxyResultBody<GetTenantUserResponse>> {
240
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
241
+ return await this.httpRequest.get(url);
242
+ }
243
+
244
+ /** PUT /internal/tenants/{tenantId}/users/{cognitoSub} — renombra a un usuario. */
245
+ async updateTenantUser(
246
+ tenantId: string,
247
+ cognitoSub: string,
248
+ input: UpdateTenantUserRequest,
249
+ ): Promise<APIGatewayProxyResultBody<TenantUserResponse>> {
250
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
251
+ return await this.httpRequest.put(url, input);
252
+ }
253
+
254
+ /** DELETE /internal/tenants/{tenantId}/users/{cognitoSub} — borra a un usuario. El `actedBy` viaja en el cuerpo. */
255
+ async deleteTenantUser(
256
+ tenantId: string,
257
+ cognitoSub: string,
258
+ input: DeleteTenantUserRequest,
259
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>> {
260
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}`;
261
+ return await this._deleteWithBody(url, input);
262
+ }
263
+
264
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/disable — suspende a un usuario. */
265
+ async disableTenantUser(
266
+ tenantId: string,
267
+ cognitoSub: string,
268
+ input: DisableTenantUserRequest,
269
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>> {
270
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/disable`;
271
+ return await this.httpRequest.post(url, input);
272
+ }
273
+
274
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/enable — reactiva a un usuario suspendido. */
275
+ async enableTenantUser(
276
+ tenantId: string,
277
+ cognitoSub: string,
278
+ input: EnableTenantUserRequest,
279
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>> {
280
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/enable`;
281
+ return await this.httpRequest.post(url, input);
282
+ }
283
+
284
+ /**
285
+ * POST /internal/tenants/{tenantId}/users/{cognitoSub}/password-reset — resetea la contraseña.
286
+ * Devuelve la contraseña temporal en claro; no se manda correo.
287
+ */
288
+ async resetTenantUserPassword(
289
+ tenantId: string,
290
+ cognitoSub: string,
291
+ input: ResetTenantUserPasswordRequest,
292
+ ): Promise<APIGatewayProxyResultBody<ResetTenantUserPasswordResponse>> {
293
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/password-reset`;
294
+ return await this.httpRequest.post(url, input);
295
+ }
296
+
297
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/mfa-reset — resetea el MFA de un usuario. */
298
+ async resetTenantUserMfa(
299
+ tenantId: string,
300
+ cognitoSub: string,
301
+ input: ResetTenantUserMfaRequest,
302
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>> {
303
+ const url = `${this._tenantUsersUrl(tenantId)}/${encodeURIComponent(cognitoSub)}/mfa-reset`;
304
+ return await this.httpRequest.post(url, input);
305
+ }
306
+
307
+ /** GET /internal/tenants/{tenantId}/roles — catálogo de roles del tenant, para armar el selector de asignación. */
308
+ async listTenantRoles(
309
+ tenantId: string,
310
+ ): Promise<APIGatewayProxyResultBody<ListTenantRolesResponse>> {
311
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/roles`;
312
+ return await this.httpRequest.get(url);
313
+ }
314
+
315
+ /** POST /internal/tenants/{tenantId}/role-assignments — asigna un rol a un usuario en un scope. */
316
+ async assignTenantRole(
317
+ tenantId: string,
318
+ input: AssignTenantRoleRequest,
319
+ ): Promise<APIGatewayProxyResultBody<AssignTenantRoleResponse>> {
320
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/role-assignments`;
321
+ return await this.httpRequest.post(url, input);
322
+ }
323
+
324
+ /**
325
+ * POST /internal/tenants/{tenantId}/role-assignments/{assignmentId}/revoke — revoca una asignación.
326
+ * El `cognitoSub` va en el cuerpo porque es parte de la llave de la tabla de asignaciones.
327
+ */
328
+ async revokeTenantRole(
329
+ tenantId: string,
330
+ assignmentId: string,
331
+ input: RevokeTenantRoleRequest,
332
+ ): Promise<APIGatewayProxyResultBody<RevokeTenantRoleResponse>> {
333
+ const url = `${this.baseUrl}/internal/tenants/${encodeURIComponent(tenantId)}/role-assignments/${encodeURIComponent(assignmentId)}/revoke`;
334
+ return await this.httpRequest.post(url, input);
335
+ }
129
336
  }
@@ -1,4 +1,9 @@
1
- import { ApiGatewayResponse, ResolvedPermissions, ResolveInput } from "@fiado/gateway-adapter";
1
+ import {
2
+ APIGatewayProxyResultBody,
3
+ ApiGatewayResponse,
4
+ ResolvedPermissions,
5
+ ResolveInput,
6
+ } from "@fiado/gateway-adapter";
2
7
  import {
3
8
  DefineNextChallengeRequest,
4
9
  DefineNextChallengeResponse,
@@ -16,6 +21,27 @@ import {
16
21
  CreateTenantUserRequest,
17
22
  CreateTenantUserResponse,
18
23
  UserProfileResponse,
24
+ ListLevelEntitiesResponse,
25
+ LevelEntityResponse,
26
+ UpdateLevelEntityRequest,
27
+ DeleteLevelEntityRequest,
28
+ DeleteLevelEntityResponse,
29
+ ListTenantUsersResponse,
30
+ GetTenantUserResponse,
31
+ TenantUserResponse,
32
+ TenantUserAckResponse,
33
+ UpdateTenantUserRequest,
34
+ DeleteTenantUserRequest,
35
+ DisableTenantUserRequest,
36
+ EnableTenantUserRequest,
37
+ ResetTenantUserPasswordRequest,
38
+ ResetTenantUserPasswordResponse,
39
+ ResetTenantUserMfaRequest,
40
+ ListTenantRolesResponse,
41
+ AssignTenantRoleRequest,
42
+ AssignTenantRoleResponse,
43
+ RevokeTenantRoleRequest,
44
+ RevokeTenantRoleResponse,
19
45
  } from "@fiado/type-kit/bin/platformRbac/index.js";
20
46
 
21
47
  /**
@@ -26,8 +52,8 @@ import {
26
52
  * `defineAuthChallenge`, `createAuthChallenge` y `verifyAuthChallengeResponse`
27
53
  * configurados en cada User Pool aprovisionado por la saga `TenantOnboardingManager`.
28
54
  *
29
- * Patrón de retorno: `Promise<ApiGatewayResponse<T>>` sin unwrap (v4 canonical Fiado).
30
- * El consumer accede `result.body.data` para llegar al payload tipado.
55
+ * Devuelve el body HTTP crudo `{ code, date, msg, data }`, con el payload en `.data`: el tipo honesto es
56
+ * el de los métodos de administración. Los `ApiGatewayResponse<T>` mienten y quedan por TD-AI-003.
31
57
  *
32
58
  * Env var requerida en el consumer: `PLATFORM_RBAC_BUSINESS_URL`.
33
59
  * El template.yml del consumer la setea con:
@@ -128,4 +154,123 @@ export interface IPlatformRbacBusinessApi {
128
154
  cognitoSub: string,
129
155
  tenantId: string,
130
156
  ): Promise<ApiGatewayResponse<UserProfileResponse>>;
157
+
158
+ // ── Administración de RBAC para el hub de agentes (grupos, usuarios y roles) ──
159
+ // Estos métodos declaran el shape REAL de retorno: `APIGatewayProxyResultBody<T>` = el body
160
+ // HTTP crudo del ApiResponse de rbac, con el payload en `.data` (TD-AI-003).
161
+
162
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities — lista los grupos de un nivel; `parentId` filtra por los hijos de un grupo. */
163
+ listLevelEntities(
164
+ tenantId: string,
165
+ level: PermissionScope,
166
+ parentId?: string,
167
+ ): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>>;
168
+
169
+ /** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
170
+ getLevelEntity(
171
+ tenantId: string,
172
+ level: PermissionScope,
173
+ id: string,
174
+ ): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
175
+
176
+ /** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo. */
177
+ updateLevelEntity(
178
+ tenantId: string,
179
+ level: PermissionScope,
180
+ id: string,
181
+ input: UpdateLevelEntityRequest,
182
+ ): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
183
+
184
+ /** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
185
+ deleteLevelEntity(
186
+ tenantId: string,
187
+ level: PermissionScope,
188
+ id: string,
189
+ input: DeleteLevelEntityRequest,
190
+ ): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>>;
191
+
192
+ /**
193
+ * GET /internal/tenants/{tenantId}/users — lista los usuarios del tenant.
194
+ * El filtro `email` es lo que permite adoptar una cuenta que ya existía: antes de crear un
195
+ * usuario se pregunta si ese correo ya tiene uno.
196
+ */
197
+ listTenantUsers(
198
+ tenantId: string,
199
+ email?: string,
200
+ ): Promise<APIGatewayProxyResultBody<ListTenantUsersResponse>>;
201
+
202
+ /**
203
+ * GET /internal/tenants/{tenantId}/users/{cognitoSub} — detalle de un usuario.
204
+ * De aquí sale el `assignmentId` que hace falta para revocar un rol.
205
+ */
206
+ getTenantUser(
207
+ tenantId: string,
208
+ cognitoSub: string,
209
+ ): Promise<APIGatewayProxyResultBody<GetTenantUserResponse>>;
210
+
211
+ /** PUT /internal/tenants/{tenantId}/users/{cognitoSub} — renombra a un usuario. */
212
+ updateTenantUser(
213
+ tenantId: string,
214
+ cognitoSub: string,
215
+ input: UpdateTenantUserRequest,
216
+ ): Promise<APIGatewayProxyResultBody<TenantUserResponse>>;
217
+
218
+ /** DELETE /internal/tenants/{tenantId}/users/{cognitoSub} — borra a un usuario. El `actedBy` viaja en el cuerpo. */
219
+ deleteTenantUser(
220
+ tenantId: string,
221
+ cognitoSub: string,
222
+ input: DeleteTenantUserRequest,
223
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
224
+
225
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/disable — suspende a un usuario. */
226
+ disableTenantUser(
227
+ tenantId: string,
228
+ cognitoSub: string,
229
+ input: DisableTenantUserRequest,
230
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
231
+
232
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/enable — reactiva a un usuario suspendido. */
233
+ enableTenantUser(
234
+ tenantId: string,
235
+ cognitoSub: string,
236
+ input: EnableTenantUserRequest,
237
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
238
+
239
+ /**
240
+ * POST /internal/tenants/{tenantId}/users/{cognitoSub}/password-reset — resetea la contraseña.
241
+ * Devuelve la contraseña temporal en claro; no se manda correo.
242
+ */
243
+ resetTenantUserPassword(
244
+ tenantId: string,
245
+ cognitoSub: string,
246
+ input: ResetTenantUserPasswordRequest,
247
+ ): Promise<APIGatewayProxyResultBody<ResetTenantUserPasswordResponse>>;
248
+
249
+ /** POST /internal/tenants/{tenantId}/users/{cognitoSub}/mfa-reset — resetea el MFA de un usuario. */
250
+ resetTenantUserMfa(
251
+ tenantId: string,
252
+ cognitoSub: string,
253
+ input: ResetTenantUserMfaRequest,
254
+ ): Promise<APIGatewayProxyResultBody<TenantUserAckResponse>>;
255
+
256
+ /** GET /internal/tenants/{tenantId}/roles — catálogo de roles del tenant, para armar el selector de asignación. */
257
+ listTenantRoles(
258
+ tenantId: string,
259
+ ): Promise<APIGatewayProxyResultBody<ListTenantRolesResponse>>;
260
+
261
+ /** POST /internal/tenants/{tenantId}/role-assignments — asigna un rol a un usuario en un scope. */
262
+ assignTenantRole(
263
+ tenantId: string,
264
+ input: AssignTenantRoleRequest,
265
+ ): Promise<APIGatewayProxyResultBody<AssignTenantRoleResponse>>;
266
+
267
+ /**
268
+ * POST /internal/tenants/{tenantId}/role-assignments/{assignmentId}/revoke — revoca una asignación.
269
+ * El `cognitoSub` va en el cuerpo porque es parte de la llave de la tabla de asignaciones.
270
+ */
271
+ revokeTenantRole(
272
+ tenantId: string,
273
+ assignmentId: string,
274
+ input: RevokeTenantRoleRequest,
275
+ ): Promise<APIGatewayProxyResultBody<RevokeTenantRoleResponse>>;
131
276
  }