Emberdocs
applets/APPLET_SPEC.md

Reference

Ember applet API and manifest reference

This is the public reference for building an Ember applet. For packaging tools, JSON schemas, TypeScript declarations, and the WASI backend template, use the repository's docs/applets author kit.

Start here#

An applet is a signed .ember-applet ZIP containing static web files and an applet.json manifest. Its HTML entry page must load Ember's SDK before its own script:

<script src="/_ember/sdk.js"></script>
<script src="app.js" defer></script>

The SDK supplies a read-only window.ember object. Applets cannot use Tauri, the host filesystem, environment variables, raw sockets, native processes, or remote and inline scripts. Bundle all required assets in the package.

Use manifest version 1 for an offline applet with optional JSON storage. Use version 2 for every other capability. Version 2 requires a capabilities object, even when it is empty. It does not use the version 1 permissions array.

{
  "manifestVersion": 2,
  "id": "com.example.my-applet",
  "name": "My applet",
  "description": "A small Ember applet.",
  "version": "1.0.0",
  "entry": "index.html",
  "capabilities": { "storage": {} }
}

id uses reverse-domain form and stays stable across updates. version uses major.minor.patch. entry names a packaged HTML file. Supported icons are applet, notes, focus, weather, and calendar.

API and required capability#

APIManifest declarationWhat it does
ember.storagev1: permissions: ["storage"]; v2: capabilities.storageApplet-scoped JSON storage with get, set, delete, keys, and clear. Limit: 5 MB.
ember.settings.get()settings manifest fieldReads only preferences the applet declared.
ember.http.request()capabilities.network.requestsSends native HTTPS requests that bypass CORS. Declare each origin, method, and applet-controlled header.
Browser fetchnetwork.browserFetchAllows declared browser destinations. CORS still applies.
WebSocketnetwork.websocketsAllows declared wss:// destinations.
Remote images and medianetwork.images, network.mediaAdds declared origins to the applet's content policy.
ember.secretscapabilities.credentials.slotsPrompts for, checks, or deletes OS-backed secrets. Applet code never receives plaintext.
ember.auth.authorize()auth, an external-navigation origin, token HTTP grant, and credential slotRuns OAuth authorization-code flow with PKCE and stores the access token in the declared slot.
ember.external.openUrl()externalNavigation.originsOpens a declared HTTPS URL in the system browser.
ember.windowwindow.fullscreenReads or changes fullscreen state for the applet window.
ember.terminalterminalOpens an in-memory guest terminal with built-in commands only. No host files, process execution, or network access.
ember.backendbackend plus any needed capabilitiesInvokes a WASI component or subscribes to its events.
ember.extensionextensionsCalls exactly granted methods from a trusted, installed native extension.

All SDK calls can reject with ember.EmberApiError. Check error.code for policy and request errors such as permission_denied, origin_not_allowed, method_not_allowed, header_not_allowed, invalid_request, timeout, rate_limited, and backend_error.

Networking and credentials#

Origins must be HTTPS, except WebSockets which use WSS. Wildcards replace only the leftmost subdomain label. Paths, query strings, credentials, HTTP, and unencrypted WebSockets are not allowed in a declaration.

Native HTTP allows GET, POST, PUT, PATCH, DELETE, and HEAD. Request bodies can be text, JSON, Base64, or form data. Ember limits an applet to 120 native requests per minute, 2 MB request bodies, 10 MB responses, 30-second timeouts, and five validated redirects. It blocks local and private network addresses and has no cookie jar.

Credential slots attach a protected value as a header, form field, or query parameter to their declared HTTPS targets. Name each used slot in the request's credentials array. Keep publisher-wide service secrets on a server you control. A desktop package cannot keep one secret private.

Backends, workers, and background activity#

A backend is a WASI component with runtime: "wasiComponent", a packaged .wasm entry, interface version 1, a lifecycle, and 16 to 256 MiB of memory. It has no inherited environment, filesystem, raw network, or process access. The background lifecycle also requires capabilities.background.

Declare dedicated or blob workers under capabilities.workers. Remote worker code remains forbidden.

Signing, package limits, and updates#

Create an Ed25519 key outside the applet folder, then package from the Ember repository root:

npm run applet:key -- ../publisher-key.pem
npm run applet:pack -- path/to/my-applet ../publisher-key.pem

The packager creates the integrity and signature files. Do not edit the archive after packaging. Packages and their uncompressed contents may not exceed 25 MB. They may contain at most 512 files, with an 8 MB limit per file. Ember verifies paths, hashes, signature, manifest, and package limits before installation.

Ember pins the first publisher key used for an applet ID. Every update must use that same private key and receives another capability review. Install the exact generated .ember-applet in Ember's Library and test it before publishing.