Referencia de la API en la nube de AfterPack

El contrato de red de api.afterpack.dev: autenticación, el endpoint de ofuscación por lotes, límites, límites de tasa, el presupuesto de tiempo del build y los códigos de diagnóstico que un cliente tiene que manejar.

@afterpack/core y cada plugin de framework ya hablan este protocolo en cuanto hay una clave Pro configurada: autenticación, streaming multipart, reintentos, todo. Lee esto cuando conectes una integración de CI propia, escribas un cliente fuera de los paquetes oficiales o depures una respuesta que tus herramientas no esperaban.

URL base y versionado

URL base: https://api.afterpack.dev/v1/

La API se versiona en la URL y v1 es la única versión. Dentro de ella, los campos de respuesta se añaden, nunca se eliminan ni cambian de significado; un cambio incompatible saldría como v2, en paralelo. GET /v1/version devuelve la versión desplegada y el entorno, y GET / es una comprobación de disponibilidad sin autenticación.

Compatibilidad de clientes

Dos cabeceras de solicitud opcionales, ambas ignoradas, nunca un 400, cuando faltan o están mal formadas; un script de curl, o un cliente anterior a estas cabeceras, no se ve afectado en ningún caso:

CabeceraContiene
X-AfterPack-Client-VersionLa versión npm instalada de @afterpack/core, para un cliente construido sobre él.
X-AfterPack-ClientEl paquete que llama y su versión, p. ej. afterpack/0.1.0 o @afterpack/vite/0.1.0.

La comparación se hace solo en el servidor, sobre MAJOR.MINOR.PATCH, ignorando cualquier sufijo de prerelease (0.1.0-rc.3 se lee como 0.1.0); una versión que este servidor no puede interpretar, o la ausencia de cabecera, se acepta siempre. Cada respuesta lleva X-AfterPack-Min-Client-Version mientras haya un mínimo configurado, así que un script puede comprobar su propia situación sin provocar un rechazo. Se comprueba justo después de autenticar la clave, antes de leer el cuerpo de la solicitud:

  • Por debajo del mínimo configurado: 426 DIAG_CLIENT_UPGRADE_REQUIRED, con details.minVersion.
  • Durante una ventana de retirada: 410 DIAG_API_SUNSET.

Ninguno de los dos está configurado por defecto. Un espacio de trabajo solo los ve cuando AfterPack fija una versión mínima o una fecha de retirada para esta API.

La respuesta también puede llevar un array notices de nivel superior en un batch-summary correcto, en cualquier cuerpo de error y en el 202 de telemetría del nivel Free: {severity, code, message, url?}, como máximo 5, cada message limitado a 500 caracteres. Una severity desconocida se lee como advertencia; no hay nada que hacer aparte de mostrarla.

Autenticación

Dos credenciales, y no son intercambiables.

CredencialCabeceraA qué da acceso
Una clave de API ProAuthorization: Bearer ap_v1_<...>POST /v1/obfuscate/batch y GET /v1/usage. La clave deduce su propio espacio de trabajo, así que no se envía ningún id de espacio de trabajo.
Una sesión del panelLa sesión que conserva tu navegador después de iniciar sesiónTodo lo que gestiona una cuenta: crear, listar y revocar claves, planes, facturación, miembros, proyectos. Requiere un workspaceId explícito y un rol en el espacio de trabajo.

Una clave es una credencial de build. Ofusca e informa de su propio uso, y no puede emitir otra clave, leer la facturación ni modificar un espacio de trabajo. Esa contención es precisamente la idea: una clave guardada en CI puede gastar tu asignación, y nada más.

Las claves son ap_v1_ seguido de 40 caracteres base62. Una clave se muestra exactamente una vez, al crearla. En el servidor solo se guarda un hash HMAC-SHA256 con sal, así que una clave en claro nunca se puede recuperar después, solo revocar. Emite una en el panel.

Pro cloud batch-obfuscation request flowYour buildplugin / CLIPOST /v1/obfuscate/batchAuthorization: Bearer ap_…AfterPack cloudobfuscates each fileobfuscation is in-memoryper-file resultsBatch summarycounts + timingYour build outputprotected & written backFiles stream back one by one; the source sent for obfuscation is processed in memory, not stored.

Endpoints

POST /v1/obfuscate/batch

El único endpoint de ofuscación. Una llamada es un build. Los resultados llegan en streaming a medida que termina cada archivo.

Solicitud: multipart/form-data.

ParteObligatoriaDescripción
batchSíEl manifiesto del lote, como parte de tipo cadena JSON.
una parte por archivoSíEl código fuente JS, bajo el partName que declara su entrada del manifiesto.
una parte por source mapOpcionalUn source map previo, bajo el sourceMapPartName de esa entrada.

El manifiesto es:

{
  "version": "1",
  "files": [
    {
      "filePath": "assets/app-a1b2c3.js",  // echoed back on the result part
      "partName": "file0",                 // names the form part carrying the source
      "sourceMapPartName": "map0",         // optional
      "config": { "regions": [ /* ... */ ] } // optional, per-file
    }
  ],
  "config": { "preset": "hard", "seed": 42 }, // batch-level EngineConfig
  "git": { "commitSha": "…", "ref": "…" }     // optional build attribution
}

El config a nivel de lote es un objeto de configuración del motor: cada clave de Configuración, incluidas preset, seed y regions. filePath y git son campos del manifiesto; consulta la forma del manifiesto de arriba.

filePath no puede contener comillas ni caracteres CR/LF. Se copia tal cual en el Content-Disposition de la parte de resultado, y una ruta mal formada se rechaza.

curl https://api.afterpack.dev/v1/obfuscate/batch \
  -H "Authorization: Bearer ap_v1_xxx" \
  -F 'batch={"version":"1","files":[{"filePath":"dist/app.js","partName":"file0"}],"config":{"preset":"hard"}}' \
  -F file0=@dist/app.js

Respuesta: 200 con un cuerpo multipart/mixed en streaming. Las partes llegan a medida que terminan los archivos, así que escribe cada una a disco en cuanto llegue en lugar de acumular el lote en memoria:

  1. Una parte obfuscation-result por archivo: { version, filePath, status, output, outputMap, processingManifest }. Si falla, output y outputMap son null y processingManifest.diagnostics explica el motivo.
  2. Una parte final batch-summary: { version, totalFiles, successCount, failureCount, engineVersion, results, totalDurationMs, totalInputBytes, totalOutputBytes }.

El fallo de un archivo no aborta el lote. Todos los demás archivos siguen llegando con normalidad, y el resumen informa del reparto.

GET /v1/usage

Uso y asignación del espacio de trabajo. Es la única lectura de tipo gestión que puede hacer una clave, para que un job de CI pueda comprobar su asignación restante. Acepta o bien una clave de API Pro (que deduce su propio espacio de trabajo) o bien una sesión del panel más ?workspaceId=.

{
  "tier": "indie",
  "workspace": { "id": "…", "name": "…" },
  "allowance": { "remainingMb": 412.5, "totalMb": 500, "resetAt": "…" },
  "credits": { "balanceMb": 20 },
  "subscription": { "status": "active", "plan": "indie_monthly", "renewsAt": "…", "graceUntil": null, "lapsed": false },
  "recentBuilds": [
    {
      "buildId": "…", "builtAt": "…", "fileCount": 61,
      "totalBytes": 3145728, "outputBytes": 9437184,
      "meteredMb": 3.0, "allowanceMb": 3.0, "creditMb": 0, "overageMb": 0,
      "projectId": "…", "cloudMs": 39120
    }
  ]
}

outputBytes y cloudMs son null cuando se desconocen, nunca 0 como sustituto. allowanceMb / creditMb / overageMb son el reparto de meteredMb entre las tres bolsas.

Límites

LímiteValor
Por archivo50 MB
Archivos por lote200
Bytes totales del lote500 MB

Si se supera cualquiera de ellos, la solicitud se rechaza entera con 413 y DIAG_FILE_TOO_LARGE o DIAG_BATCH_TOO_LARGE, antes de medir nada. Las mismas cifras, desde el lado del panel, están en Claves de API.

Límites de tasa

Se cuentan sobre una ventana móvil de 60 segundos, por clave y por IP de cliente:

ÁmbitoLímite
Por clave, espacio de trabajo gratuito10 solicitudes / min
Por clave, espacio de trabajo de pago100 solicitudes / min
Por IP de cliente100 solicitudes / min

Superar cualquiera de los dos ámbitos devuelve 429 con DIAG_RATE_LIMITED y una cabecera Retry-After con el tiempo que falta hasta que la ventana que lo provocó se vacíe de verdad. Si la propia comprobación del límite de tasa no puede ejecutarse, la solicitud falla de forma segura (fail closed) con 503 DIAG_RATE_CHECK_UNAVAILABLE y Retry-After: 5.

El presupuesto de tiempo del build

Todo un bundle se ofusca dentro de una sola invocación, con un límite de CPU de 120 segundos. Dos presupuestos de tiempo real mantienen el build dentro de ese límite.

TranscurridoQué pasa
45 sSe detiene la captura del Protection Map. La ofuscación continúa hasta el final; el mapa guardado se marca como parcial con el motivo de omisión deadline.
90 sNo se empieza ningún archivo más. Cada archivo restante devuelve un fallo explícito con DIAG_BUILD_DEADLINE que indica cuántos de N se completaron, y el stream se cierra con normalidad.

Si alcanzas el segundo presupuesto, divide el lote.

Códigos de diagnóstico

Los errores llevan un code estable junto al estado HTTP, en el mismo espacio de nombres DIAG_* que los diagnósticos del propio motor. Los que un cliente tiene que manejar:

CódigoEstadoSignificado
DIAG_INVALID_KEY401Clave ausente o no reconocida.
DIAG_KEY_REVOKED401La clave fue revocada.
DIAG_KEY_EXPIRED401La clave ha superado su expiresAt.
DIAG_KEY_OUT_OF_SCOPE403Clave válida, usada desde una IP fuera de su lista allowedIPs.
DIAG_CLIENT_UPGRADE_REQUIRED426Cliente por debajo de la versión mínima configurada. Incluye details.minVersion. Consulta Compatibilidad de clientes.
DIAG_API_SUNSET410Esta versión de la API está retirada. Consulta Compatibilidad de clientes.
DIAG_ENTITLEMENT_LAPSED402Pago de la suscripción vencido. Incluye graceUntil y upgradeUrl.
DIAG_QUOTA_EXHAUSTED402La asignación + créditos (+ el tope de exceso, si está activado) no cubren este build. Incluye remainingMb, requestedMb y un reason que distingue "sin cuota" de "tope de exceso alcanzado".
DIAG_RATE_LIMITED429Consulta los límites de tasa más arriba. Incluye retryAfterSeconds.
DIAG_RATE_CHECK_UNAVAILABLE503Falló la comprobación del límite de tasa; falla de forma segura. Reintenta.
DIAG_INVALID_MANIFEST400Cuerpo multipart mal formado, falta la parte batch, o un manifiesto que no pasa la validación.
DIAG_FILE_TOO_LARGE413Un archivo de más de 50 MB.
DIAG_BATCH_TOO_LARGE413Más de 200 archivos o más de 500 MB en total.
DIAG_BUILD_DEADLINEn/aPor archivo, dentro de un stream 200. Al build se le agotó el presupuesto de tiempo antes de empezar este archivo.
DIAG_ENGINE_FAILUREn/aPor archivo, dentro de un stream 200. El motor lanzó un error con este archivo.

Los dos últimos no son estados HTTP. Llegan como status: "failure" en una parte obfuscation-result dentro de una respuesta correcta. Un cliente que solo mira el estado HTTP confundirá un build con fallos parciales con uno limpio.

Reintentos y backoff

EstadoReintentableComportamiento
400, 401, 402, 403, 413NoCorrige la solicitud.
429Una vezRespeta Retry-After exactamente, con un tope de 120 s; un segundo 429 falla de forma segura.
500NoBug del motor; repórtalo.
503, 504Sí1 s, 4 s, 16 s (tres reintentos, cuatro intentos en total) y después falla de forma segura.

El cliente oficial aplica además un timeout de 120 segundos a toda la solicitud, y trata los fallos de DNS, TLS y de conexión reiniciada como nube inalcanzable en lugar de reintentarlos indefinidamente.

Ciclo de vida de la clave, desde el lado del cliente

Emitir, restringir y revocar son operaciones del panel. Dos comportamientos importan al código que llama a esta API:

  • Revocación a mitad de build. Una clave revocada mientras un lote está en streaming devuelve 401 solo en la siguiente solicitud; lo que ya está en curso termina con normalidad.
  • Una clave restringida a una lista de IP devuelve 403 DIAG_KEY_OUT_OF_SCOPE cuando se usa desde cualquier otro sitio, distinto del 401 que recibe una clave inválida o revocada, para que un cliente pueda distinguir "clave equivocada" de "clave correcta, lugar equivocado".
La medición es atómica y va primero

Un lote que no cabe en las bolsas del espacio de trabajo se rechaza entero antes de despachar ningún archivo, con las bolsas intactas: nunca procesado a medias, nunca facturado a medias. Es la forma a nivel de lote de la regla de fallo seguro.

Tratamiento del código fuente

El código fuente enviado para ofuscar se procesa solo en memoria, durante esa única solicitud, y nunca se escribe en disco, en logs ni en un índice de búsqueda. Los logs contienen ids de solicitud, recuentos de archivos, totales de bytes y códigos de diagnóstico, nunca contenido de archivos, nombres de identificadores ni valores de constantes.

Un artefacto sobrevive a la solicitud: el Protection Map que se guarda por build para el panel. Contiene tu código fuente original, coloreado según cuánta transformación recibió cada token. Está activado por defecto en cada proyecto, solo lo pueden leer los miembros del espacio de trabajo propietario, se conserva un año y los últimos 500 builds por proyecto (lo que se agote antes) y se puede desactivar en los ajustes del proyecto. Todos los detalles, en Privacidad y tratamiento de datos.

Siguiente