Autenticación y convenciones
Convenciones de la API de administración: autenticación con bearer, roles y capacidades, mutaciones idempotentes, paginación y el sobre de error.
- Disponibilidad: Planificado
- Evidencia: Leído del código fuente
- Referencia
Autenticación
Cada solicitud lleva el token bearer de la autoridad compartida de Beyond, la misma identidad que usa Workspace:
GET /v1/session HTTP/1.1
Authorization: Bearer <token>El CDN no guarda cuentas ni membresías. Una organización es un equipo de Workspace, y el CDN almacena solo identificadores opacos de organización y de usuario. Esta API nunca acepta tokens de invitado de aplicaciones privadas.
| Operación | Solicitud | Capacidad | Reintento |
|---|---|---|---|
session.read |
GET /v1/session |
Cualquier usuario con sesión iniciada | |
organization.read |
GET /v1/organizations/{organization} |
application.read |
session.read responde el usuario que inició sesión, sus organizaciones, roles, capacidades de CDN y un resumen del plan. organization.read responde el contexto de una organización de quien llama. Cuando no se puede contactar a la autoridad, la respuesta es 502 UPSTREAM_UNAVAILABLE, nunca un rechazo ni una aprobación.
Roles y capacidades
Los roles vienen de la autoridad: owner, admin, developer, viewer y none. El CDN es dueño de una tabla de capacidades sobre esos roles, y cada operación indica la capacidad que exige.
| Capacidad | Permite | owner | admin | developer | viewer |
|---|---|---|---|---|---|
application.read |
Leer aplicaciones, targets, registros, grafos, inventarios, trabajos, releases, entornos, dominios y cierres de backend | Sí | Sí | Sí | Sí |
application.manage |
Crear, cambiar y eliminar aplicaciones y sus targets, y vincular una aplicación a un proyecto de Beyond o desvincularla | Sí | Sí | Sí | |
release.prepare |
Registrar selecciones, preparar candidatos, cancelar trabajos y vincular el entorno testing |
Sí | Sí | Sí | |
release.promote |
Vincular production: promover, revertir y retirar releases |
Sí | Sí | ||
access.manage |
Cambiar la visibilidad y administrar permisos de invitado | Sí | Sí | ||
domain.manage |
Reservar el subdominio de pruebas y administrar dominios propios | Sí | Sí | ||
providers.manage |
Leer el resumen sin credenciales de los proveedores de registro de la organización, y establecer o quitar sus ajustes y sus credenciales de solo escritura | Sí | Sí | ||
usage.read |
Leer consumo, cuotas, plan, habilitaciones, crédito y libro de crédito | Sí | Sí | Sí | |
plan.request |
Entrar en la lista de espera de premium o salir de ella | Sí | Sí | ||
events.subscribe |
Obtener permisos de tiempo real, reproducir eventos y leer instantáneas | Sí | Sí | Sí | Sí |
El rol none no tiene ninguna capacidad y oculta los recursos de la organización.
Dos operaciones exigen una capacidad que depende del entorno sobre el que actúan: la promoción y la reversión necesitan release.prepare para testing y release.promote para production. El contrato lo expresa de forma legible por máquina, x-beyond-capability-by, junto a x-beyond-capability.
Las negativas siguen una regla. Un recurso que quien llama no puede ver responde 404 NOT_FOUND, para no revelar su existencia. Un recurso visible sobre el que el rol no puede actuar responde 403 FORBIDDEN.
Las operaciones bajo /v1/platform pertenecen al backoffice de la plataforma. Exigen una capacidad de operador de plataforma que ningún rol de organización implica, y responden NOT_FOUND a todos los demás. No se documentan aquí.
Proveedores de registro
Una organización puede resolver paquetes desde registros distintos del público, por ejemplo un registro privado para un ámbito de npm. Los ajustes pertenecen a la organización y los usan los registros que se ejecuten después. Los grafos fijados y los releases existentes nunca cambian.
La versión 1 lee registros compatibles con npm accesibles por Internet. Un registro accesible solo a través de una red privada o una VPN queda fuera de la versión 1: los workers llegan solo a direcciones públicas de Internet, y una dirección de registro que no puede serlo se rechaza al guardarla.
| Operación | Solicitud | Capacidad | Reintento |
|---|---|---|---|
providers.list |
GET /v1/organizations/{organization}/providers |
providers.manage |
|
providers.set |
PUT /v1/organizations/{organization}/providers/{provider} |
providers.manage |
natural |
providers.remove |
DELETE /v1/organizations/{organization}/providers/{provider} |
providers.manage |
natural |
{provider} es default, para todo paquete sin un ajuste de ámbito, o un ámbito de npm como @acme.
{ "registry": "https://<registry host>", "token": "<registry token>" }| Miembro | Obligatorio | Regla |
|---|---|---|
registry |
Sí | La dirección base, http o https, sin información de usuario, consulta ni fragmento. Puede llevar un prefijo de ruta. Una dirección de un rango de loopback, privado, de enlace local u otro reservado, o un nombre que solo responde un resolvedor local (localhost, *.internal, una sola etiqueta), es 400 VALIDATION_FAILED con el mensaje must be a public Internet address. Una dirección que esta versión no puede usar como registro compatible con npm responde 422 UNSUPPORTED_INPUT. |
token |
No | El token bearer del registro. Bearer es el único modo de autenticación de esta versión. Una solicitud sin token deja el registro sin credencial. |
Quitar un proveedor hace que los paquetes de ese ámbito vuelvan a resolverse desde el registro predeterminado. Quitar un proveedor que no existe responde lo mismo.
La visibilidad pertenece al paquete
Si un paquete es público se decide para cada paquete, no por la credencial con la que se leyó:
- Un paquete leído sin credencial es público.
- Un paquete leído con credencial es público solo cuando el mismo registro, consultado de forma anónima, responde la misma versión con la misma integridad y el mismo archivo comprimido, y el archivo comprimido en sí responde de forma anónima. Cualquier duda lo mantiene privado: un registro responde igual "no encontrado" y "no permitido" a un cliente anónimo.
- Un repositorio Git o una URL de archivo comprimido leídos con credencial son privados.
Un paquete público produce salidas públicas, aunque se haya usado tu token para leerlo, y se descarga sin el token. Un paquete privado se queda en tu organización, y también toda salida que lo lee, incluido el módulo de un paquete público que lo importa. Una aplicación privada no vuelve privadas sus dependencias públicas. Quitar un token no vuelve públicos los bytes que ya se retuvieron. Consulta Preparación e inventario.
Reintentos y cambios concurrentes
Cada mutación indica cómo tolera un reintento:
| Tipo | Cómo funciona | Lo usan |
|---|---|---|
key |
El encabezado Idempotency-Key es obligatorio. Un reintento con la misma clave y la misma solicitud responde el resultado original sin repetir el trabajo. La misma clave con una solicitud distinta es 409 IDEMPOTENCY_MISMATCH; una clave ausente es 400 IDEMPOTENCY_REQUIRED. |
La creación de aplicaciones, registros, preparaciones, dominios propios y permisos de invitado |
version |
La solicitud lleva expected_version. Si no es la versión actual del recurso, no cambia nada y la respuesta es 409 CONFLICT_VERSION con details.current. |
El cambio de una aplicación, la promoción y la reversión |
natural |
Repetir la solicitud deja el mismo estado | Definir y quitar targets, eliminar, cancelar, retirar, reservar el subdominio de pruebas, verificar un dominio, revocar un permiso, establecer y quitar un proveedor, pedir un ticket de miembro |
Un Idempotency-Key cumple ^[A-Za-z0-9_.:-]{8,128}$, lo elige el cliente, es único por cada mutación que se quiere hacer y su ámbito es la organización de quien llama. Si una solicitud agota su tiempo de espera, envíala de nuevo con la misma clave: nunca generes una clave nueva para un reintento.
Paginación
Las operaciones de listado aceptan limit (de 1 a 200, 50 de forma predeterminada) y after. Una página responde items y, cuando hay más, next. Envía next de vuelta como after. Los cursores son opacos.
Identificadores
| Tipo | Forma |
|---|---|
| Recursos del CDN (aplicaciones, releases, trabajos, …) | <kind>_<random>, que cumple ^[a-z][a-z0-9]*_[A-Za-z0-9]{6,40}$, por ejemplo job_Prep0001x |
| Organizaciones y usuarios | Valores opacos que pertenecen a la autoridad. El CDN nunca los interpreta. |
| Fechas y horas | Fecha y hora según RFC 3339 |
| Digests | sha256- seguido de 64 caracteres hexadecimales |
Errores
Los fallos usan un solo sobre, con la misma forma que el del contrato de entrega. details reemplaza a diagnostics:
{ "error": { "code": "CONFLICT_VERSION", "message": "…", "details": { "current": 7 } } }| Estado | Código | Significado |
|---|---|---|
400 |
VALIDATION_FAILED |
La solicitud no sigue el esquema; details.fields enumera los problemas |
400 |
IDEMPOTENCY_REQUIRED |
La mutación exige un encabezado Idempotency-Key |
401 |
UNAUTHENTICATED |
Ninguna sesión válida acompaña la solicitud |
402 |
CREDIT_INSUFFICIENT |
El crédito disponible de la organización no cubre la reserva |
403 |
FORBIDDEN |
El recurso es visible y el rol no tiene la capacidad |
403 |
ACCESS_REVOKED |
La sesión, la membresía, el permiso de invitado o el permiso de tiempo real fue revocado o venció |
403 |
ADMISSION_REQUIRED |
El solicitante es un miembro cuyo rol permite la operación, pero no fue admitido a la gestión y la preparación de CDN, o su admisión fue revocada; details.policy nombra la política de admisión. Ver Admisión interna de personas |
403 |
ENTITLEMENT_REQUIRED |
El plan de la organización no incluye la capacidad; details.entitlement la nombra |
404 |
NOT_FOUND |
El recurso no existe, o quien llama no debe saber que existe |
409 |
CONFLICT_VERSION |
expected_version está desactualizado; details.current trae el actual |
409 |
IDEMPOTENCY_MISMATCH |
La clave ya se usó con una solicitud distinta |
409 |
STATE_INVALID |
El recurso no está en un estado que permita la operación |
409 |
NAME_CONFLICT |
El nombre ya está en uso dentro de la organización |
409 |
DOMAIN_CONFLICT, DOMAIN_UNVERIFIED |
Consulta Dominios |
409 |
QUOTA_EXCEEDED |
Se superaría una cuota; details.quota la nombra |
409 |
PROJECT_CONFLICT |
La aplicación ya está vinculada a otro proyecto de Beyond; details.current lo nombra. Consulta El proyecto de una aplicación |
409 |
PROJECT_INACTIVE |
El proyecto de Beyond está archivado o eliminado; details.state lleva su estado |
410 |
CURSOR_EXPIRED |
Un cursor de reproducción es anterior a los eventos retenidos |
413 |
PAYLOAD_TOO_LARGE |
El cuerpo de la solicitud supera el tamaño aceptado |
422 |
UNSUPPORTED_INPUT |
Una entrada bien formada que esta versión no puede procesar: proveedor, forma de publicación, formato o forma de dependencia |
422 |
LIMIT_EXCEEDED |
La solicitud supera un límite configurado y no se reintenta automáticamente |
422 |
PROJECT_UNKNOWN |
El proyecto de Beyond no existe o no pertenece a la organización de la aplicación; nunca se distingue entre las dos |
501 |
NOT_IMPLEMENTED |
La operación existe en el contrato y esta instancia del servicio no monta su área, o la integración que necesita no está configurada; details.operation la nombra |
429 |
RATE_LIMITED |
Demasiadas solicitudes; respeta Retry-After |
500 |
INTERNAL |
Fallo inesperado. El mensaje nunca contiene secretos. |
502 |
UPSTREAM_UNAVAILABLE |
Un registro, la autoridad, Beyond Projects u otro servicio externo no respondió. Nunca es un rechazo ni una aprobación |
503 |
BUDGET_EXHAUSTED |
El presupuesto global de admisión no acepta trabajo nuevo en este momento |
503 |
UNAVAILABLE |
El servicio no puede atender la solicitud en este momento |
Los códigos son estables y nunca se traducen. Los motivos por los que un trabajo puede fallar son un vocabulario aparte que viaja dentro de documentos y eventos; consulta Trabajos.
Ningún GET inicia trabajo
Ningún GET de esta API, ni ningún GET de la entrega publicada, inicia, reanuda o programa trabajo. Solo las operaciones POST explícitas crean trabajos. Leer un trabajo, un release o un inventario tantas veces como quieras es seguro.