Media (Out-of-Band Bytes)
Images/videos never cross the wire protocol (the frame cap is 16 MiB).
vendor.media demonstrates the intended pattern:
- The host picks/captures a file natively and returns its path to the worklet.
- The worklet mounts it on the loopback server under an unguessable id and returns only the URL. The native path never reaches the page.
- The web layer loads the URL directly — same-origin, cookie-authenticated.
One serving implementation for every runtime.
Web side
Section titled “Web side”import type { PluginBus } from '@ekrooh/bare/core';import { mediaEvents } from '@ekrooh/bare/plugins/media/events';
declare const bus: PluginBus; // createPluginBus(messenger), see Transportsdeclare const img: HTMLImageElement;
const [err, result] = await bus.invoke(mediaEvents.media.pick('image'));if (!err) { // Check the URL is a same-origin path before using it (the reference app's // `safeMediaUrl` in examples/web/media-url.ts does this). const url = new URL(result.url, location.href); if (url.origin === location.origin) img.src = url.href;}The builders pass a 5-minute invoke timeout, because the native picker is user-mediated.
Plugin side
Section titled “Plugin side”createMediaPlugin delegates the pick/capture to the host via
HOST_INVOKE_REQUEST (with a host deadline of 4 min 55 s, just under the
page’s timeout), then mounts the returned path under a CSPRNG id:
import crypto from 'bare-crypto';
const id = `${kind}-${crypto.randomBytes(16).toString('base64url')}`;deps.staticServer.mount(`/media/${id}`, path);const url = await deps.staticServer.url(`/media/${id}`);return ok({ url }); // never the native pathNever derive a mount id from Date.now() or a counter: any holder of the
session could then guess other mounted files. At most 4 media mounts stay
live; the oldest is unmounted first.
Host side
Section titled “Host side”The Android reference host wires a real native picker/camera; the iOS host
uses PHPickerViewController + UIImagePickerController. The host returns
{ path } to the worklet — bytes stay in the sandbox, served by the worklet.
A host error with a code outside the canonical ErrorCode set reaches the
page as HOST_ERROR, and its message is capped at 500 characters.
Events
Section titled “Events”media.pick and media.capture, each taking { kind?: 'image' | 'video' }
(any other kind is refused with PLUGIN_ERROR before it reaches the host)
and returning { url }.