# Instalar y restaurar archivos .wuapp

Empaqueta, verifica, instala, monta y actualiza una app con firma y grants definidos por el host.

Esta página describe WU Framework `4.0.0`. Consulta la [migración a Framework 4.0 y CLI 1.2](/es/docs/guides/releases/) antes de actualizar un proyecto existente.

Un archivo `.wuapp` contiene una app construida, su manifest, archivos y firma opcional. Se instala en Cache Storage bajo `/@wuapp/<name>@<version>/`. Es una ruta virtual del mismo origen del host; la firma acredita la clave aceptada y la integridad verificada, no convierte el código instalado en código aislado de otro origen.

<span class="section-anchor" id="section-1"></span>

## Preparar el paquete

```sh
wu build --native
wu pack --keygen keys/catalog.pem --json
wu pack catalog --version 1.2.0 --sign keys/catalog.pem --out catalog-1.2.0.wuapp
wu serve 4100
```

La clave privada se conserva fuera del contenido público. Copia la clave pública JWK del resultado a `catalog-public-key.json` en el host. El nombre `catalog` debe existir en `dist/wu-manifest.json`. Consulta [wu pack](/es/docs/cli/pack/) para opciones, formato y errores.

<span class="section-anchor" id="section-2"></span>

## Instalar y montar

```js
import { wu } from 'wu-framework/core';
import 'wu-framework/wuapp';

await wu.init({ apps: [] });
const publicKey = await fetch('/catalog-public-key.json').then(r => r.json());
const installed = await wu.wuapps.install('/catalog-1.2.0.wuapp', {
  trust: [publicKey],
  grants: ['events.emit:catalog:*'],
});
const worker = await wu.wuapps.check();
if (!worker.ok) throw new Error(worker.reason);
await wu.mount(installed.name, '#catalog-slot');
```

Sirve el archivo y la clave pública por HTTPS o localhost y crea `#catalog-slot` en el shell. El Service Worker generado por `wu build --native` debe controlar la página; después de la primera visita puede requerirse una recarga. `check().ok` comprueba que existe un controlador, no que cualquier Service Worker ajeno implemente la ruta. Verifica también la respuesta HTTP de la entrada instalada.

`source` admite URL, `File`/`Blob`, `ArrayBuffer`, `Uint8Array` u objeto parseado. Antes de escribir en caché, el instalador valida forma, rutas, firma ECDSA P-256 y SHA-256 por archivo. El host define `trust` y `grants`; `trust: "any"` acepta cualquier clave firmante y `allowUnsigned: true` permite paquetes sin firma. `frameworkBase` cambia el prefijo `/@modules/` cuando el host sirve los módulos compartidos en otra ruta.

<span class="section-anchor" id="section-3"></span>

## Restaurar, actualizar y retirar

```js
await wu.wuapps.restore();
const inventory = await wu.wuapps.installed();

await wu.unmount('catalog', { force: true });
await wu.wuapps.install('/catalog-1.3.0.wuapp', {
  trust: [publicKey], grants: ['events.emit:catalog:*'],
});
await wu.mount('catalog', '#catalog-slot');

await wu.unmount('catalog', { force: true });
const removed = await wu.wuapps.uninstall('catalog');
```

`restore()` registra las entradas persistidas y devuelve las restauradas; no las monta. `installed()` consulta el índice guardado. Instalar otra versión reemplaza la anterior; actualizar o desinstalar una app montada u oculta rechaza con `WU_WUAPP_MOUNTED`. Desmonta completamente antes. Los eventos son `wuapp:installed` y `wuapp:uninstalled`.

Los errores distinguen `WU_WUAPP_INVALID`, `WU_WUAPP_UNSIGNED`, `WU_WUAPP_UNTRUSTED`, `WU_WUAPP_BAD_SIGNATURE`, `WU_WUAPP_INTEGRITY` y `WU_WUAPP_NO_CACHE`. Guardar el paquete no demuestra que sus módulos monten: el host sigue necesitando los módulos compartidos, los grants correctos y una ruta atendida por el worker.

<span class="section-anchor" id="section-4"></span>

## Integridad y reemplazo en 4.0

El campo `type` del paquete no determina el MIME: se deduce de la extensión usando la tabla de `wu pack` y se sirve con `nosniff`. Las rutas rechazan segmentos reservados, incluido `__proto__`, y el payload firmado se construye sin prototipo.

Instalar sobre un nombre registrado por el host requiere `{ replace: true }`; de lo contrario falla con `WU_WUAPP_NAME_TAKEN`. La actualización de una app instalada sigue permitida después de desmontarla. `restore()` valida cada entrada persistida y nunca sustituye un registro del host.

`restore({ grants })` acepta un array de grants o una función `(entry) => grants` definida por el host. Si se omite, utiliza los grants guardados al instalar. Define esa opción cuando no quieras recuperar autoridad desde el índice de localStorage.