El Protection Map es la forma de verificar tu protección: tu código fuente original, con cada token coloreado según cuánta transformación recibió.
$ npx afterpack@latest dist/Obtienes este mapa:
entitlements.js, 54 lines, built at the light preset with a directive around the signature check. Click any token to see what was applied to it.Cómo leerlo
Los tokens se colorean según la puntuación de complejidad: cuánta transformación recibió cada token, el número cuyo objetivo fija complexity. Cuanto más rojo el token, más transformación recibió:
| Color | Puntuación de complejidad |
|---|---|
| Gris | Sin complejidad añadida. El código que se deja legible a propósito también es gris. |
| Verde | Menos de 4 |
| Amarillo | De 4 a 7 |
| Rojo | De 7 a 10 |
| Rojo oscuro | Más de 10 |
El color muestra cuánto se aplicó. Selecciona un token y el inspector muestra por lo que pasó su región: las transformaciones aplicadas, cuánto de la región cubren y por qué quedó legible el código que sigue siéndolo. Un mapa de un motor anterior no tiene puntuaciones por token y muestra todo el código protegido en un solo color. Una declaración que el motor reescribió, como var a let o una función a una función flecha, aparece en una línea "Also rewritten". Un formateador deshace esas reescrituras, así que no añaden complejidad ni color.
La transformación más fuerte que tocó un token determina su etiqueta de clase de reversión, que se muestra junto a sus transformaciones. Son clases de atacante estático: describen a qué se enfrenta alguien que lee los bytes. Cuatro etiquetas:
| Etiqueta | Clase de reversión | Qué significa |
|---|---|---|
| Preservado | Ninguna | Sin tocar: imports de terceros, exportaciones públicas, todo lo excluido o marcado con skip. Se deja legible para que los llamadores sigan resolviéndose. |
| Renombrado y codificado | polinómico-inyectivo | Identificadores renombrados, cadenas codificadas. La estructura se puede recuperar con un esfuerzo real; derrota a los explicadores con IA y a los desofuscadores estándar. |
| Aplanado y fusionado | polinómico-no inyectivo | Flujo de control aplanado, identidades fusionadas. Un atacante recupera un cálculo equivalente, no tus nombres y valores originales. |
| Destruido y fusionado | fusión destructiva | Descompuesto y fusionado a lo largo del bundle. Un lector estático recupera un programa equivalente, no cuál es el original que escribiste. No disponible; consulta más abajo. |
Pasa el cursor sobre un token para ver las transformaciones que se le aplicaron, agrupadas por categoría (por ejemplo, aplanamiento del flujo de control), junto a la clase en la que queda. Pruébalo en la demo en vivo.
El número detrás del color es la puntuación de complejidad. Una región que recibió menos transformación de la que esperabas es la que debes subir con su preset o marcar con preset=hard.
Una región protegida resiste una lectura estática: grep, herramientas de AST, un LLM a ciegas. Un valor que usa el código en ejecución sigue siendo observable para un atacante que lo ejecuta en un runtime instrumentado. Mantén los secretos de verdadero valor en el servidor. El mapa muestra a qué se enfrenta un lector estático, nada más.
Marca el código de alto valor
El mapa muestra más transformación donde la pides. Dos formas de directiva cubren casi todos los casos. Un marcador en línea abarca el literal o la expresión del resto de su línea. Un marcador de bloque solo en su línea abre una región que cierra el /* @afterpack end */ correspondiente; todo lo que queda entre ambos está cubierto, incluidos cuerpos de función completos.
// A single literal — API keys, license secrets, sensitive constants:
const SECRET = /* @afterpack preset=extreme */ "EXPECTED_LICENSE_SECRET";
// A whole function — validators, anti-cheat, payment flow.
// The opener is alone on its line; the matching end closes the block:
/* @afterpack preset=hard */
export function checkLicense(token: string): LicenseClaims | null {
// ...everything in here is at complexity target 12...
}
/* @afterpack end */
// A span of several statements:
/* @afterpack preset=extreme */
const claims = JSON.parse(atob(payload));
if (claims.secret !== SECRET) return null;
/* @afterpack end */Si una región que marcaste no muestra más transformación que el código que la rodea, la directiva no tuvo efecto. Normalmente un compilador eliminó el comentario antes de que AfterPack lo viera. AfterPack informa de ello. La gramática completa de las directivas está en Directivas; los marcadores usados arriba son preset=hard y preset=extreme.
Free frente a Pro
Free ya renombra y codifica con el preset light por defecto, y a partir de medium también aplana y fusiona dentro de un archivo. Por sí solo abarca las dos clases, polinómico-inyectivo y polinómico-no inyectivo.
Pro añade la selección quirúrgica por región, que te permite pintar exactamente la docena de funciones en las que equivocarse sale caro, además de las dos transformaciones de endurecimiento (selfIntegrity, comparisonHardening). Free cubre bien el grueso de un código real; Pro es lo que usas alrededor de las comprobaciones de licencia y los secretos. Compáralos lado a lado en Niveles.
La clase destruido y fusionado no está disponible. Consulta Clases de reversión.
Genera el tuyo
$ npx afterpack@latest dist/Obtienes la misma vista interactiva generada sobre tu propio código fuente: un archivo HTML estático, sin inicio de sesión ni telemetría, que puedes adjuntar a un PR. El mapa muestra tu código fuente original, así que, por defecto, solo se escribe cuando tu build emitió un source map que el motor pueda encadenar, y no en CI (CI=true o CI=1). En otro caso es opcional: pasa protectionMap: { enabled: true } en las opciones de tu plugin y el plugin activa por ti el source map del bundler. Pasa --protectionMap.enabled=false para omitirlo. Apunta a tu directorio de build: Next.js escribe en .next/, Nuxt en .output/ y la mayoría de los bundlers en dist/.
Dónde vive tu mapa
Una ejecución local escribe el mapa en .afterpack/ en tu máquina y no envía nada a ningún sitio. El directorio lleva su propio .gitignore, así que git lo ignora. La CLI se niega a escribir el mapa en una ruta que se sirve. Un Protection Map publicado contiene todo tu código fuente. Nunca lo publiques.
Un build Pro en la nube funciona de otra manera. El mapa lo genera el motor en la nube que hizo la ofuscación, el único motor que respeta tus directivas preset=hard, preset=extreme y skip, así que es el único mapa que puede mostrar su efecto. AfterPack lo conserva, de modo que abres el mapa de cualquier build reciente desde el panel en lugar de volver a generarlo.
Un Protection Map es tu código, coloreado. En un build Pro en la nube se guarda en la infraestructura de AfterPack y lo puede leer cualquier miembro del espacio de trabajo al que pertenece el proyecto. Si tu código fuente no debe poder leerse en todo el espacio de trabajo, desactívalo. Consulta más abajo.
Qué se guarda, exactamente:
- Los datos del mapa de cada build: tu código fuente original más las métricas por token que hay detrás de los colores, en Cloudflare R2, cifrados en reposo con AES-256, junto con una fila de cifras resumen (cobertura, inflación, recuentos de puntos débiles) que grafica el panel. Tu salida ofuscada no se guarda.
- Acotado a un proyecto, aquel al que está vinculada la clave del build.
- Solo lo pueden leer los miembros de ese espacio de trabajo. No es público, no se indexa y no tiene enlace para compartir.
- Se conserva un año y los últimos 500 builds por proyecto, lo que se agote antes. Una tarea horaria elimina todo lo que supera cualquiera de los dos límites. La ventana de un año permite comparar una versión con la anterior. El límite de 500 builds evita que un proyecto que compila muchas veces al día acumule un año de copias de su código fuente; en un proyecto así, ese límite es el que se alcanza primero.
- Un build que no pudo guardar un mapa deja en su lugar una nota, que registra el motivo y los tamaños implicados, nunca tu código ni un nombre de archivo. Se conserva y se elimina con el mismo calendario, y el panel muestra ese build como no guardado en lugar de como uno que nunca se ejecutó.
- Pasada esa ventana, el panel lo indica. Las notas y los mapas caducan juntos; tu historial de builds no. Un build más antiguo que la retención anterior aparece como sin registro.
Desactivarlo
Guardar mapas está activado por defecto, por proyecto. Un administrador del espacio de trabajo puede desactivarlo en los ajustes del proyecto. A partir de entonces, los nuevos builds en la nube de ese proyecto no generan ni guardan nada; los mapas ya guardados caducan según la retención anterior en lugar de desaparecer de inmediato. Los Protection Maps locales no se ven afectados en ningún caso: esa vía nunca toca la red.
Los gráficos de tu panel siguen funcionando. Desactivar esto deja de conservar tu código fuente. No deja de registrar lo que midió un build. La cobertura, la inflación, la complejidad y el tiempo de build no contienen código, y se siguen registrando y graficando en un proyecto con la captura desactivada. El recuento de puntos débiles es la única excepción, porque se cuenta dentro de un mapa guardado. La salida ofuscada no cambia.
Un mapa guardado es lo único que AfterPack conserva en reposo que contiene tu código fuente. Todo lo demás de un build en la nube permanece en memoria lo que dura una petición. Consulta Privacidad y manejo de datos.
Siguiente
- Clases de reversión: las tres clases que hay detrás de estas etiquetas, por transformación.
- Buenas prácticas: patrones para marcar las regiones adecuadas.
- Configuración: gramática de directivas, reglas por archivo, presets.
- Cómo funciona AfterPack: las tres clases de reversión en profundidad.
- Modelo de amenaza: el eje estático frente a dinámico que presuponen estas etiquetas.
- Privacidad y manejo de datos: qué guarda un build en la nube, durante cuánto tiempo y quién puede leerlo.
- Directivas: cada marcador que puedes poner delante de una región.
- Pro: qué desbloquea el marcado por región y los mapas guardados.
- Demo en vivo: la misma vista, sobre código de ejemplo, sin instalar nada.