# Install and restore .wuapp files

Package, verify, install, mount and update an app with a signature and host-defined grants.

This page describes WU Framework `4.0.0`. Read the [Framework 4.0 and CLI 1.2 migration guide](/docs/guides/releases/) before upgrading an existing project.

A `.wuapp` file contains one built app, its manifest, files and optional signature. It installs into Cache Storage under `/@wuapp/<name>@<version>/`. This is a virtual path on the host origin; the signature establishes the accepted key and verified integrity, not isolation on another origin.

<span id="preparar-el-paquete"></span>

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

## Prepare the package

```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
```

Keep the private key outside public content. Copy the public JWK from the result into `catalog-public-key.json` in the host. The name `catalog` must exist in `dist/wu-manifest.json`. See [wu pack](/docs/cli/pack/) for options, format and errors.

<span id="instalar-y-montar"></span>

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

## Install and mount

```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');
```

Serve the file and public key over HTTPS or localhost and create `#catalog-slot` in the shell. The Service Worker generated by `wu build --native` must control the page; the first visit may require a reload. `check().ok` checks for a controller, not whether an arbitrary Service Worker implements the route. Also verify the installed entry HTTP response.

`source` accepts a URL, `File`/`Blob`, `ArrayBuffer`, `Uint8Array` or parsed object. Before writing to cache, installation validates structure, paths, the ECDSA P-256 signature and each file SHA-256. The host sets `trust` and `grants`; `trust: "any"` accepts any signing key and `allowUnsigned: true` permits unsigned packages. `frameworkBase` replaces `/@modules/` when the host serves shared modules elsewhere.

<span id="restaurar-actualizar-y-retirar"></span>

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

## Restore, update and remove

```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()` registers persisted entries and returns the restored ones; it does not mount them. `installed()` reads the saved index. Installing another version replaces the previous one; updating or uninstalling a mounted or hidden app rejects with `WU_WUAPP_MOUNTED`. Fully unmount first. Events are `wuapp:installed` and `wuapp:uninstalled`.

Errors distinguish `WU_WUAPP_INVALID`, `WU_WUAPP_UNSIGNED`, `WU_WUAPP_UNTRUSTED`, `WU_WUAPP_BAD_SIGNATURE`, `WU_WUAPP_INTEGRITY` and `WU_WUAPP_NO_CACHE`. Saving a package does not prove its modules mount: the host still needs shared modules, correct grants and a worker-served route.

<span id="integridad-y-reemplazo-en-40"></span>

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

## Integrity and replacement in 4.0

The package’s `type` field does not determine MIME: it is derived from the extension using the `wu pack` table and served with `nosniff`. Paths reject reserved segments, including `__proto__`, and the signed payload is built without a prototype.

Installing over a name registered by the host requires `{ replace: true }`; otherwise it fails with `WU_WUAPP_NAME_TAKEN`. Updating an installed app remains allowed after unmounting it. `restore()` validates every persisted entry and never replaces a host registration.

`restore({ grants })` accepts an array of grants or a host-defined `(entry) => grants` function. When omitted, it uses the grants saved at installation. Set this option when you do not want to recover authority from the localStorage index.