Skip to content

Apps

A captured app is an HTML page the owner opens, running in a sandboxed frame with no network.

apps: {
"incidents.html": {
handlers: ["oncall.open", "oncall.acknowledge"],
resources: ["apps/incidents.html.assets/app.css", "apps/incidents.html.assets/app.js"],
},
},
  • The key is the page’s file name, [A-Za-z0-9][A-Za-z0-9_.-]{0,119} ending in .html or .htm, and synth copies apps/<key> from the realm, refusing the app when the page is missing. At most 32 apps, and each apps/<key>.app.json is at most 8 KiB.
  • handlers lists what the page may call, each a declared namespace.verb, at most 32, each once. It may be empty. The compiler does not check these names; synth refuses one the realm does not declare. Each listed handler still needs its own approval, and the owner approves the app itself separately.
  • resources lists up to 16 stylesheets and scripts from apps/<key>.assets/, .css or .js only, each listed once, and synth copies each one. The host inlines each one in its own <style> or <script> block ahead of the page. A stylesheet containing </style or a script containing </script is refused.
  • The host operator sets the host’s size limits. The defaults are 10 MiB for the page, 16 resources, 10 MiB for any one resource and 10 MiB for all resources together. Synth holds an app to the same defaults, and the --app-* flags or a profile change what it holds the app to for a host with other limits (see app limits and profiles).

Inside the page, realm.call(handler, args) calls a handler and resolves to its result:

const incidents = await realm.call("oncall.open", {});
await realm.call("oncall.acknowledge", { incidentId: incidents.items[0].id });
  • One call runs at a time. A second call made while one is waiting rejects straight away, so await each call before starting the next.
  • A call gives up after about two minutes. Every refusal rejects with the same message.
  • The page cannot fetch, open sockets, load remote scripts, styles, images or fonts, read the owner’s cookies or storage, open popups or submit forms. Scripts may be inline and may use eval. Images and fonts work as data: or blob: URLs. Bundle everything at build time.
  • If the page reloads or navigates its own frame, the bridge stops answering until the owner opens the app again.

The session, approval and revocation rules are under captured browser apps.