# Build and Sign <Badge type="warning" text="Not yet released" />

A Mini App that signs people in (see [Sign-in](https://docs.micromeet.ai/miniapp-sdk/auth.md)) is delivered as a **signed package**: its files packed into one `app.asar`, a `manifest.json`, and Micromeet's signature over both. Cowork checks the signature when it opens the Mini App and checks every file against it when the page reads it; a changed file closes the Mini App. Cowork does not open a package whose signature is missing or does not verify; it tells the person the Mini App is not certified.

## The package

```text
manifest.json         { appId, name, version, version_code, entry, asar, domains, asarHeaderSha256, signature }
app.asar              the built pages, scripts and styles, each with a SHA-256 digest in its header
app.asar.unpacked/    large media (video, audio), outside app.asar; their digests stay in its header
INSTALL.md            optional: steps for the agent that installs it
```

| Field | Description |
|---|---|
| `appId` | Lower-case reverse domain, such as `ai.example.app`; issued when Micromeet registers the Mini App |
| `name` | String, or `{ zh, en }`; 1–60 characters |
| `version` | Letters, digits, `.`, `+`, `-`; at most 32 |
| `version_code` | 12 digits, the build time `YYMMDDHHmmss` |
| `entry` | The entry page inside `app.asar`; default `index.html` |
| `domains` | The server domains the page sends requests to; written from the plugin's `domains` option (see [Server domains](#server-domains)) |
| `asarHeaderSha256` · `signature` | Written by the tools below; do not edit |

Cowork serves the pages from `miniapp://<appId>/` with the content policy `script-src 'self'`: put every script in a file (no inline `<script>`), and absolute paths such as `/assets/app.js` work. A signed Mini App keeps separate storage for each Cowork account, so one person never sees what another stored.

## Build it

The `@micromeet-ai/miniapp-sdk` package (Micromeet's GitLab package registry; ask Micromeet for access) adds a Vite plugin that writes the package after every build:

```js
// vite.config.js
import { defineConfig } from 'vite';
import { miniapp } from '@micromeet-ai/miniapp-sdk/vite';

export default defineConfig({
  plugins: [miniapp({ appId: 'ai.example.app', name: { en: 'Example', zh: '示例' }, unpackDir: 'media' })]
});
```

`vite build` then writes `miniapp-package/`; the version comes from `package.json`. Files named `.DS_Store`, `__MACOSX`, `.git` or `node_modules` are left out. Without Vite, `micromeet-miniapp pack --src dist --out miniapp-package --app-id … --name … --version …` does the same.

## Server domains

A Mini App signs people in together with its own backend: the page sends the one-time code there (see [Sign-in](https://docs.micromeet.ai/miniapp-sdk/auth.md)). Your backend's origins are the Mini App's **server domains**, and a version without a verified one cannot sign anyone in. Only a Mini App that signs people in with Micromeet needs them; they do not limit what else the page requests.

1. Tell Micromeet the origin of your backend, such as `https://api.example.com`: HTTPS, a host name, no path; up to 20 per Mini App.
2. Micromeet gives you a file, `https://api.example.com/micromeet-miniapp-<16 characters>.txt`, holding a token. Serve it at that address over HTTPS with status 200 and no redirect.
3. Micromeet verifies the domain by fetching the file. Keep the file there: when it is gone, the domain stops counting and sign-ins stop.
4. List the domains in the package:

```js
miniapp({ appId: 'ai.example.app', name: { en: 'Example' }, domains: ['https://api.example.com'] })
```

Without Vite: `micromeet-miniapp pack … --domain https://api.example.com`. The domains are signed with the version, so a changed list is a new version. For development, `http://localhost:<port>` or `http://127.0.0.1:<port>` needs no file where Micromeet allows it.

## Have Micromeet sign it

Micromeet registers each version and signs it. Micromeet's own Core reads `app.asar`, checks every file against its digest and signs the header; the signature is written into `manifest.json`. Before handing a package over, check it the way Cowork and Micromeet will:

```bash
micromeet-miniapp verify miniapp-package            # the package
micromeet-miniapp verify miniapp-package --signed   # after signing: the signature verifies
```

A version cannot be registered twice: change `version` for every new build you hand over.

## Deliver it

```bash
micromeet-miniapp zip miniapp-package    # → ai.example.app-1.0.0.zip
```

The person installs the zip in Cowork by asking the agent (`miniapp_install`). Cowork keeps each version in its own folder and removes the older one once its tabs are closed. A signed Mini App can also go inside a package of extensions and skills; Cowork checks it the same way each time it opens.

| Limit | |
|---|---|
| `app.asar` | 512 MB; put media in `app.asar.unpacked/` (`unpackDir` or `unpack`) |
| `app.asar.unpacked/` | 100,000 files, 8 GB |

## Related

- [Build a Sign-in Mini App](https://docs.micromeet.ai/miniapp-sdk/sign-in-guide.md): From registration to a working sign-in
- [Package Spec](https://docs.micromeet.ai/miniapp-sdk/package-spec.md): Every rule a package must meet, and who checks it
- [Sign-in](https://docs.micromeet.ai/miniapp-sdk/auth.md): Sign a person in from the Mini App
- [Overview](https://docs.micromeet.ai/miniapp-sdk/overview.md): All modules of the Mini App SDK
