/**
* 🔴 **El contrato del diálogo de acceso, y por qué está diseñado POR CAPACIDADES.**
*
* El kit no sabe —ni debe saber— cómo decide sus permisos el host. Su contrato de lectura
* (`WidgetDefinition.permissions`) recibe una *decisión ya tomada*: cinco verbos. Este contrato es la
* otra mitad, la de escritura, y tiene el mismo problema al revés: para pintar un formulario hay que
* saber qué campos existen.
*
* La respuesta no es asumir el modelo de un host. Es que **el host declare qué soporta** y el diálogo
* pinte solo eso:
*
* - sin `searchPeople`, el sujeto se teclea en vez de buscarse;
* - sin `getPolicy`/`savePolicy`, la pestaña de visibilidad no existe;
* - sin `expiry`, no se pinta el vencimiento.
*
* Un host que solo reparta lectura a personas nombradas obtiene un diálogo de una pestaña y tres
* controles, y no ve ni una casilla de algo que su backend no implementa. Añadir una capacidad
* mañana es **aditivo**: no rompe a quien no la declare.
*
* ⚠️ **El kit no habla HTTP.** Todas las operaciones son funciones que provee el host. Quien las
* implementa contra su API vive en el host, igual que `IWidgetAccessPolicy` en el backend del
* componente: el modelo de acceso es del host, el formulario es del kit.
*/
import type { DashboardCategoryOption } from '../components/WidgetBuilder/categories';
/** A quién se le concede. `user` es el mínimo; los otros dos solo si el host los declara. */
export type WidgetGrantSubjectType = 'user' | 'permission' | 'module';
/** Los niveles, de menor a mayor. Un host puede declarar un subconjunto. */
export type WidgetGrantLevel = 'viewer' | 'editor' | 'owner';
/** Los estados de visibilidad que el diálogo sabe pintar. */
export type WidgetVisibilityState = 'private' | 'module' | 'restricted';
/** Alcance de la caché del dato. Solo se pinta si el host lo declara. */
export type WidgetDataScopeState = 'shared' | 'perUser';
/** Una persona del directorio del host. `nombre` puede venir vacío: se cae al id. */
export interface WidgetAccessPerson {
id: string;
nombre?: string;
email?: string;
}
/** Una fila de «quién tiene acceso». */
export interface WidgetGrantRow {
subjectType: WidgetGrantSubjectType;
subjectId: string;
/**
* Nombre legible del sujeto, si el host puede resolverlo. Cuando falta se pinta el id — es lo que
* pasa hoy en Comercial mientras el directorio de usuarios devuelve marcadores.
*/
subjectLabel?: string;
level: WidgetGrantLevel;
grantedAt?: string;
grantedBy?: string;
/** `null` o ausente = sin vencimiento. */
expiresAt?: string | null;
/**
* El acceso existe y **no le abre nada** a su destinatario, porque le falta una capacidad de más
* arriba. Es la señal que convierte la revisión en una lista de excepciones en vez de una lista
* que alguien debe acordarse de mirar.
*/
inert?: boolean;
}
/** Lo que el host devuelve al conceder: si quedó inerte, y cualquier aviso que quiera mostrar. */
export interface WidgetGrantResult {
inert?: boolean;
/** Texto ya resuelto por el host. El kit no traduce mensajes de un modelo que no conoce. */
warning?: string;
}
/** La política del widget: quién lo alcanza y con qué alcance se cachea su dato. */
export interface WidgetPolicy {
visibility: WidgetVisibilityState;
dataScope?: WidgetDataScopeState;
}
/** Una opción de vocabulario del host (módulos o permisos como sujeto). */
export interface WidgetAccessTerm {
id: string;
label: string;
}
/**
* Lo que el host declara que su modelo soporta. Todo es opcional y los defaults son los mínimos:
* conceder lectura a una persona.
*/
export interface WidgetAccessCapabilities {
/** Tipos de sujeto disponibles. Default: `['user']`. */
subjects?: WidgetGrantSubjectType[];
/** Niveles disponibles, de menor a mayor. Default: `['viewer']`. */
levels?: WidgetGrantLevel[];
/**
* Módulos ofrecibles cuando `subjects` incluye `module`.
*
* 🔴 **Desde F5 el diálogo RETIRA este sujeto en todo indicador que declare vertical**, y el
* razonamiento es más fuerte que «recortar la lista»:
*
* Con un indicador en **una sola vertical**, el sujeto se queda con **exactamente un valor
* ofrecible** —la suya—, y conceder a su propia vertical **es lo mismo que no haberlo
* restringido**. Las otras dos producirían un acceso que se guarda y **no abre nada**. Una opción
* con una sola respuesta posible, y que equivale a deshacer lo que acabas de hacer, no es una
* opción: es una trampa con forma de formulario.
*
* 🟢 **Dónde sí sigue teniendo sentido, y por eso el sujeto no desaparece del contrato:** en
* un indicador **sin vertical declarada** —los personales que creó alguien antes de F1, a los que
* el servidor les vaciaba `roles_permitidos`—. Ahí no hay techo, así que conceder a un módulo
* **sí** abre algo.
*/
modules?: WidgetAccessTerm[];
/**
* 🔴 **F5 — la pareja categoría→vertical, la MISMA que consume el Constructor.**
*
* Con ella el diálogo deriva la vertical de un indicador exactamente igual que el
* Builder: de su categoría. Que las dos pantallas coincidan deja de ser disciplina y pasa a ser
* una consecuencia — no hay dos sitios donde la vertical se decida, hay uno.
*
* ⚠️ Sin esto el diálogo cae al comportamiento anterior: ofrece `modules` entero y nombra la
* visibilidad «todo el módulo» en genérico. Es aditivo a propósito; un host que no lo declare no
* se rompe, solo no mejora.
*/
categories?: DashboardCategoryOption[];
/**
* 🔴 **Permisos ofrecibles cuando `subjects` incluye `permission`.**
*
* Sin esto el sujeto se teclea, y ése era el estado en que el mecanismo central —*conceder a quien
* tenga un permiso*— llegó a la pantalla: un `` vacío, un catálogo de cientos de códigos que
* hay que saberse de memoria, y un `403` como premio por equivocarse.
*
* `allowFreeText` conserva la caja libre como respaldo para un host que no pueda enumerarlos.
*
* ⚠️ **Qué lista publicar: los permisos de QUIEN ESTÁ CONCEDIENDO**, no el catálogo entero. No es
* una simplificación: el servidor exige que uno tenga el permiso que asocia, así que ofrecer
* cualquier otro es ofrecer un rechazo. La lista correcta y la lista corta son la misma.
*/
permissions?: {
options?: WidgetAccessTerm[];
allowFreeText?: boolean;
};
/**
* Una advertencia del host junto al selector de sujeto, por tipo. El kit la pinta y no la
* interpreta: **el texto viene ya resuelto**, porque el kit no traduce mensajes de un modelo que no
* conoce. Es la misma regla que en `WidgetGrantResult.warning`.
*
* El caso que la motiva: un permiso del Access Manager autoriza *acciones*, no describe *datos*, y
* quien lo tenga por otra razón hereda el acceso sin que nadie lo haya decidido. Eso hay que
* decirlo donde se elige, no en un documento.
*/
subjectHint?: Partial>;
/** Vencimiento. Si se omite, el diálogo no lo pinta y el host decide su default. */
expiry?: {
defaultDays?: number;
allowNoExpiry?: boolean;
};
/** Visibilidades ofrecibles. Si se omite, el diálogo usa las tres del modelo. */
visibilities?: WidgetVisibilityState[];
/**
* Alcances de caché ofrecibles.
*
* 🔴 **F5.b.6 — esto SALIÓ del diálogo de acceso el 2026-09-14.** El alcance de caché **no es
* visibilidad**: no decide quién ve el indicador, sino de quién es el dato que se guarda. Tenerlo
* en la misma ventana que las dos preguntas de acceso invitaba a leerlo como una tercera, y no lo
* es. El campo se conserva en el contrato —el host lo sigue declarando y el API lo sigue
* aceptando— pero el diálogo ya no lo pinta.
*/
dataScopes?: WidgetDataScopeState[];
}
/**
* Las operaciones del host. `listGrants` es la única obligatoria junto con `grant`/`revoke`: sin
* ellas no hay nada que compartir y el diálogo no se ofrece.
*/
export interface WidgetAccessAdapter {
capabilities?: WidgetAccessCapabilities;
listGrants(widgetId: string): Promise;
grant(widgetId: string, input: {
subjectType: WidgetGrantSubjectType;
subjectId: string;
level: WidgetGrantLevel;
/** ISO, o `null` para pedir explícitamente sin vencimiento. */
expiresAt?: string | null;
}): Promise;
revoke(widgetId: string, subjectType: WidgetGrantSubjectType, subjectId: string): Promise;
/** Sin esto, el sujeto se teclea. */
searchPeople?(query: string): Promise;
/** Sin esto —o sin `savePolicy`— la pestaña de política no se pinta. */
getPolicy?(widgetId: string): Promise;
savePolicy?(widgetId: string, policy: WidgetPolicy): Promise<{
warning?: string;
} | void>;
/**
* 🔴 **F5.c — «Hoy lo ve: …». La frase que dice el RESULTADO.**
*
* Las cerraduras combinadas son difíciles de deducir mirando los controles: los grants SUMAN
* dentro del techo, y el techo de vertical manda por encima. Que el diálogo diga en qué
* queda convierte el modelo en algo que se lee en vez de calcularse.
*
* 🔴 Y ataca de frente la trampa que no tiene ninguna otra señal en pantalla:
* restringido, sin accesos, no lo ve NADIE. Es el error que alguien comete creyendo que
* restringir ya reparte.
*
* ⚠️ El texto es del HOST, y el kit solo lo pinta. Misma regla que `subjectHint` y que
* `WidgetGrantResult.warning`: el kit no conoce este modelo —no sabe qué es una vertical, ni qué
* concede un permiso del Access Manager— así que traducirlo aquí sería inventarlo. Devolver
* `undefined` es válido: la frase no se pinta.
*/
/**
* 🔴 **El rótulo y la pista de cada visibilidad, resueltos por el HOST.**
*
* ⚠️ **Se retiró el 2026-09-14 y se repuso el mismo día, y el motivo del viaje de ida y
* vuelta vale la pena.** Se retiró porque estaba **muerto**: el diálogo rediseñado no lo
* consultaba, así que un host podía implementarlo y no pasaba nada. Pero lo que el diálogo hacía
* en su lugar era **peor**: elegía el rótulo él mismo con `widget.propietario_id`, o sea aplicando
* una regla del host —*«privado SIN dueño lo ven los administradores»*— que el kit no puede
* conocer. Retirarlo convirtió una fuga reparable en una fija. Ahora se consulta de verdad.
*
* Qué decide el host aquí, y el kit no puede: qué significa `private` cuando el
* widget **no tiene dueño** (¿nadie? ¿quien administre?), y si `restricted` deja entrar a alguien
* por encima de la lista. Son reglas de su modelo de autorización, no del formulario.
*
* Devolver `undefined` —o no implementarlo— deja el texto del kit, que es deliberadamente
* **neutro**: describe el estado y **no promete quién entra**.
*/
describeVisibility?(input: {
widgetId: string;
visibility: WidgetVisibilityState;
/** Si el indicador tiene dueño. Sin dueño, «privado» no se lo reserva a nadie. */
tieneDueno: boolean;
vertical?: WidgetAccessTerm;
}): {
label?: string;
hint?: string;
} | undefined;
/**
* 🔴 **La nota de «esto lo ve alguien SIEMPRE, sin figurar en la lista».**
*
* El kit pintaba aquí un literal —*«quienes administran X lo ven siempre»*— y eso es una
* **afirmación sobre el modelo del host**: que existe un rol que salta la lista de accesos. En
* Comercial es cierto; en un host sin ese bypass sería una **garantía falsa** debajo de la lista,
* y ninguna traducción lo arregla porque el kit ya decidió pintarla.
*
* 🔴 Por eso NO tiene texto por defecto: sin respuesta del host, la nota no se pinta.
* Es la disciplina del resto del contrato —el kit no dice lo que no puede saber— y aquí importa
* más que en ningún otro sitio, porque lo que se afirmaría es justamente **quién ve el dato a
* pesar de lo que diga esta pantalla**.
*/
describeAlwaysSee?(input: {
widgetId: string;
vertical?: WidgetAccessTerm;
}): string | undefined;
describeAudience?(input: {
widgetId: string;
/** La política EN CURSO en el formulario, no la guardada: la frase sigue lo que se está eligiendo. */
policy: WidgetPolicy | null;
grants: WidgetGrantRow[];
/** La vertical del indicador, si se pudo derivar de su categoría. */
vertical?: WidgetAccessTerm;
}): string | undefined;
}
//# sourceMappingURL=types.d.ts.map