Roles
`roles.list`, `get`, `create`, `update`, `delete` y `listPermissions`.
Todos los métodos
const roles = await openemail.roles.list()const role = await openemail.roles.get('role_…') const support = await openemail.roles.create({ name: 'Support', description: 'Answers the shared inboxes and nothing else.', permissions: ['emails:send', 'threads:write', 'labels:write'],}) console.log(support.permissions) await openemail.roles.update(support.id, { permissions: [...support.permissions, 'templates:read'],}) await openemail.roles.delete(support.id, { reassignTo: 'role_…' }) const vocabulary = await openemail.roles.listPermissions()support.permissions contiene seis entradas, no tres: emails:send arrastra emails:read, threads:write arrastra threads:read y labels:write arrastra labels:read. Lee la lista devuelta en lugar de darla por supuesta.
Un rol dice lo que alguien PUEDE HACER. A qué DIRECCIONES puede hacérselo es el otro eje y vive en openemail.members. Consulta allí grantAddress y revokeAddress. «Puede enviar correo» y «puede enviar como invoices@» son frases distintas, y un espacio de trabajo que contrata a un segundo agente de soporte cambia la segunda sin tocar la primera.
Ramifica según editable y deletable, no según el nombre de builtin. Ambos son false solo para el rol de propietario, cuya lista es «todos los permisos, incluidos los que se inventen el año que viene» y se calcula en lugar de almacenarse; cualquier otro rol responde true a los dos, incluidos los cinco con los que se inicializa un espacio de trabajo. Un rol al que alguien haya cambiado el nombre sigue respondiendo correctamente a ambos, y su nombre ya no te dice nada.
update REEMPLAZA la lista de permisos. No existe una llamada para conceder uno solo, así que lee el rol, cambia la entrada que querías y envíalos todos de vuelta. Enviar un único permiso deja al rol con exactamente ese, más lo que implique.
delete necesita reassignTo en cuanto alguien tiene el rol, y viaja como parámetro de consulta porque varios entornos de ejecución y no pocos proxies descartan el cuerpo de un DELETE. El resultado informa de reassigned y keysReassigned por separado, de modo que un script puede registrar lo que hizo y no lo que pidió.
listPermissions() es GET /roles/permissions, una ruta fija situada justo donde iría el id de un rol. El cliente la codifica de forma literal en lugar de pasar la cadena por get, así que pedir un rol que de verdad se llame «permissions» pide un rol y recibe un 404, que es la respuesta honesta a lo que se escribió. scope: false marca las entradas que ninguna clave puede tener nunca.
Un rol es el techo de una clave
Una clave emitida contra un rol puede ejercer sus propios scopes INTERSECADOS con los permisos de ese rol, resueltos por solicitud en el límite del sistema. Por tanto, restringir un rol revoca sus claves en vivo, sin que ninguna se rote, y una clave sin rol no tiene techo alguno, lo que convierte un rol nulo en el estado más amplio en el que puede estar una clave, no en el más estrecho.
Por eso también roles.delete exige un destino al que mover las claves. Dejarlas huérfanas eliminaría su techo por completo, promoviendo en silencio todas las credenciales que el rol limitaba.
GET /keys/self y GET /ping informan de roleId y grantedScopes junto a los scopes efectivos, que es como se responde a «mi clave tiene emails:send y recibo insufficient_scope»: todo lo que esté en grantedScopes y falte en scopes lo quitó el rol. openemail.me.get() y openemail.me.ping() devuelven ambos, tipados.
Parámetros
namestringobligatorio- Cómo llama el espacio de trabajo al rol: de 1 a 48 caracteres, recortado antes de almacenarse. Los nombres son únicos por espacio de trabajo sin distinguir mayúsculas, así que un segundo "Support" se rechaza con `role_name_taken` (409) en lugar de crearse junto al primero.
descriptionstring- Una frase que explica para qué sirve el rol, recortada y de 240 caracteres como máximo. Una cadena que queda en blanco tras recortarla se almacena como null, de modo que una descripción de espacios vuelve como null y no como lo que enviaste.
permissionsPermission[]obligatorio- Lo que concede el rol, tomado del vocabulario que sirve `listPermissions()`; una cadena que no esté en él es un 422 sobre `permissions` en vez de descartarse en silencio, así que una errata se informa en lugar de costarte una tarde. La lista se EXPANDE a la entrada (`templates:write` almacena `templates:read` junto a él), se deduplica y se devuelve al orden canónico, así que lee la lista almacenada en la respuesta en lugar de suponer que es la que enviaste.
Respuesta
object'role'- Siempre `role`. La lápida de borrado responde con el mismo valor, el `id` del rol, `deleted: true` y los dos recuentos de reasignación, y ninguno de los demás campos que siguen.
idstring- El id del rol. Es lo que nombra el `roleId` de un miembro, aquello a lo que apunta el techo de una clave de API y lo que recibe `reassignTo` cuando se elimina este rol.
namestring- El nombre que el espacio de trabajo da al rol, recortado y único sin distinguir mayúsculas. Todos los roles salvo el de propietario pueden renombrarse, incluidos los sembrados (`builtin` dice de dónde vino una fila, no cómo tiene que seguir llamándose), así que no leas "Admin" como una promesa sobre lo que el rol contiene. Un nombre al que ya responde otro rol es `role_name_taken` (409, `param: "name"`); renombrar el de propietario es `role_immutable` (409), como cualquier otra edición suya.
descriptionstring | null- La frase que describe el rol, o null cuando no se dio ninguna. Una entrada en blanco se almacena como null tanto en create como en update, así que esto nunca es una cadena vacía.
permissionsPermission[]- Todo lo que concede el rol, ya expandido y en orden canónico, no en el orden en que alguien lo escribió. Ese orden es estructural: dos roles con los mismos permisos resultan iguales al compararlos como JSON, que es lo que permite a una pantalla de ajustes contrastarlos para decidir si Guardar está habilitado.
builtin'owner' | 'admin' | 'member' | 'viewer' | 'developer' | 'billing' | null- De cuál de los seis roles sembrados procede esta fila, o null si el espacio de trabajo la escribió él mismo. Registra el origen sembrado y no un estado: un rol sembrado se renombra, se le cambian los permisos y se elimina como cualquier otro. Ramifica según `editable` y `deletable`, no según esto. Un rol al que alguien llamó "Admin" no tiene por qué ser el sembrado, y el sembrado puede que ya no se llame así.
editableboolean- Se calcula como `builtin !== 'owner'`, así que es false solo para el rol de propietario y todo PATCH de ese rol se rechaza con `role_immutable` (409). Cualquier otro rol es editable por completo (nombre, descripción y permisos), incluidos los cinco con los que se inicializa un espacio de trabajo.
deletableboolean- Se calcula como `builtin !== 'owner'`: false solo para el rol de propietario, que devuelve `role_undeletable` (409), y true para cualquier otro rol, incluidos los sembrados. Compruébalo antes de ofrecer el botón y no después del rechazo, aunque un rol que alguien todavía tiene necesita además `reassignTo`, o el borrado es `role_in_use` (409).
membersnumber- Cuántas personas tienen este rol, contadas a partir de las filas de miembros del espacio de trabajo. El propietario no está entre ellas: no tiene fila de miembro y no se le puede asignar un rol, así que el rol de propietario informa de cero titulares aunque la lista de miembros lo muestre.
apiKeysnumber- Cuántas claves de API activas están limitadas por este rol; las claves revocadas quedan fuera del recuento, aunque un borrado reapunta todas las filas de claves que apuntan al rol, las revocadas incluidas. Es la segunda población que hay que mover antes de poder eliminar el rol, y la que nadie advierte: las claves son programas, y un programa no se queja.
createdAtstring- Cuándo se escribió la fila del rol, ISO-8601. Las filas integradas se siembran de forma diferida la primera vez que algo las necesita —una lectura de la lista de roles, la creación de un rol o la pantalla de claves de API—, y no al crear el espacio de trabajo, así que la marca de tiempo de un rol integrado indica cuándo llegó esa primera solicitud y no cuándo se creó el espacio de trabajo.
updatedAtstring- Cuándo cambió el rol por última vez, ISO-8601. Cada PATCH aceptado la actualiza, incluido uno que asigne a un campo el valor que ya tenía.