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 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.
Prepare the package
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 for options, format and errors.
Install and mount
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.
Restore, update and remove
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.
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.