Ir al contenido

Overrides

Un override redirige la URL de una sola app solo para tu navegador, persistido en una cookie. Ejecuta la app del carrito en localhost:5173 mientras el resto de la página carga desde producción; apunta una app a un despliegue de preview para revisarlo en contexto.

import { override, removeOverride, getOverrides, clearOverrides } from 'wu-framework';

Los overrides los aplica wu.init(), antes de registrar las apps: la URL sobrescrita es la que queda registrada y aquella cuyo manifiesto se descarga.

En cookies, una por app, con el nombre wu-override:<appName>:

wu-override:cart=http://localhost:5173

Ni localStorage, ni un parámetro de consulta. Se eligieron cookies porque sobreviven a una recarga, son fáciles de establecer desde devtools y están acotadas al origen. Puedes poner una a mano sin ninguna API de Wu:

document.cookie = 'wu-override:cart=http://localhost:5173; path=/; max-age=86400';

Se habilitan automáticamente solo en hostnames locales:

Hostname permitido
localhost
127.0.0.1
[::1] y ::1
0.0.0.0
cualquier cosa que acabe en .local
cualquier cosa que acabe en .localhost

Un puerto no estándar ya no cuenta como desarrollo. Antes de la v2.7 sí, lo que habilitaba automáticamente los overrides en cualquier sitio de producción servido tras un puerto como :8443. Combinado con el hecho de que una lista allowedDomains vacía permite todos los dominios, un atacante capaz de escribir una cookie podía apuntar una app a JavaScript arbitrario. El puerto no dice nada sobre el entorno, así que la heurística desapareció.

Para habilitar overrides en cualquier otro sitio tienes que decirlo explícitamente:

await wu.init({
apps: [...],
overrides: {
enabled: true,
allowedDomains: ['localhost', 'preview.example.com'],
showIndicator: true,
},
});
Opción Por defecto Significado
enabled detectado automáticamente del hostname El valor explícito siempre gana, incluido un false en desarrollo.
allowedDomains [] Hostnames a los que puede apuntar la URL de un override. Una lista vacía permite todos los dominios.
showIndicator true Mostrar el banner fijo mientras haya algún override activo.

Establece allowedDomains siempre que pongas enabled: true fuera de localhost. El valor por defecto (lista vacía) es permisivo, y esa combinación es exactamente de lo que iba el endurecimiento de la v2.7.

override(appName: string, url: string, options?: { maxAge?: number; path?: string }): void

Establece un override y escribe su cookie.

Opción Por defecto Significado
maxAge 86400 (24 h) Vida de la cookie en segundos. 0 se respeta.
path '/' Ruta de la cookie.
wu.override('cart', 'http://localhost:5173');
wu.override('header', 'https://preview-abc123.vercel.app', { maxAge: 3600 });
location.reload(); // los overrides se aplican en init()

Casos límite — esto lanza exactamente en cuatro situaciones:

Condición Mensaje
Falta appName o url [WuOverrides] appName and url are required
Overrides deshabilitados aquí [WuOverrides] Overrides are disabled in this environment. Enable with wu.init({ overrides: { enabled: true } })
URL mal formada [WuOverrides] Invalid URL: <url>
Hostname no incluido en allowedDomains [WuOverrides] Domain not allowed: "<host>". Allowed: [...]

Una URL válida es la que empieza por http://, https://, //, o la que coincide con localhost seguido opcionalmente de un puerto. Ese último patrón está anclado deliberadamente: de lo contrario localhost.evil.com pasaría como una URL de localhost.

Ten en cuenta que establecer un override no afecta a una página que ya está en marcha. Escribe la cookie; el wu.init() de la siguiente carga la aplica.

removeOverride(appName: string): void
clearOverrides(): void
wu.removeOverride('cart');
wu.clearOverrides();

Casos límite. Ninguno lanza, y ambos funcionan incluso con los overrides deshabilitados. Eliminar una app que no tenía override se registra igual que si lo tuviera.

Un tropiezo real: removeOverride() caduca la cookie con un path=/ fijado en el código. Un override establecido con un options.path personalizado no se eliminará con él — tendrás que borrar esa cookie tú mismo.

getOverrides(): Record<string, string>
wu.getOverrides(); // { cart: 'http://localhost:5173' }

Devuelve {} cuando no hay nada sobrescrito. Métodos relacionados en el subsistema:

wu.overrides.getOverrideFor(appName): string | null
wu.overrides.hasOverrides(): boolean
wu.overrides.isEnabled(): boolean
wu.overrides.refresh(): void
wu.overrides.getStats(): object

refresh() vuelve a analizar las cookies, que es lo que quieres tras editarlas en devtools o en otra pestaña. getStats() informa de { enabled, activeOverrides, overrides, allowedDomains, showIndicator, environment } — fíjate en que environment se recalcula a partir del hostname y por tanto es independiente de enabled: puede decir production mientras los overrides están activados explícitamente.

Mientras haya algún override activo y showIndicator esté activado, un banner ámbar fijo se sitúa en la parte inferior de la página:

WU OVERRIDE ACTIVE: cart → http://localhost:5173

Existe por razones de antiphishing y anticonfusión: un override significa que parte de la página no es el código que crees, y un informe de QA presentado contra una página sobrescrita no vale nada sin ese contexto.

  • Un clic oculta el banner. El override sigue activo.
  • Doble clic llama a clearOverrides().

Las cookies mal formadas se omiten en lugar de ser fatales. Las entradas se ignoran cuando el nombre o la URL están vacíos, y se avisa cuando la URL no es válida ([WuOverrides] Invalid override URL for "<app>": <url>) o el dominio no está permitido ([WuOverrides] BLOCKED: ...). Los valores de las cookies no se decodifican como URL, así que una URL que contenga un % o un ; no sobrevivirá a la ida y vuelta.

  • Solo en local, por diseño. Habilitar overrides en un hostname de producción sin establecer allowedDomains recrea la vulnerabilidad que eliminó la v2.7.
  • Requiere una recarga. Los overrides los aplica init(), no el montaje.
  • registerApp() los ignora. Una app registrada en tiempo de ejecución, después de que init() ya se haya ejecutado, no recibe el override aplicado.
  • removeOverride() asume path=/. Las cookies con ruta personalizada le sobreviven.
  • Sin comodines ni patrones. Un override por nombre de app, coincidencia exacta.
  • La cookie es entrada de confianza. Con una lista allowedDomains vacía, cualquier código o extensión capaz de escribir una cookie en tu origen puede redirigir una app a JavaScript arbitrario. Establece allowedDomains.