Embed
@superlibrary/embed mounts Superlibrary’s viewer in a host page. The artifact renders in a
sandboxed frame on the content origin; the toolbar around it lives in the host page.
The package is not published to npm. A product in another repository vendors a build: pnpm --filter @superlibrary/embed bundle writes dist/superlibrary-embed.js, one ES module, and its
types. Record the Superlibrary commit and each file’s SHA-256 beside the copy.
Mounting
Section titled “Mounting”import { mountArtifact } from '@superlibrary/embed';
const api = (path: string, init: RequestInit = {}) => // With the signed-in person's own token for the audience https://app.superlibrary.dev. fetch(`https://app.superlibrary.dev/api/v1/items/${path}`, { ...init, headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' }, }).then((res) => res.json());
const view = await mountArtifact(el, { itemId: 'itm_…', getEmbedUrl: ({ itemId, version }) => api(`${itemId}/embed`, { method: 'POST', body: JSON.stringify(version ? { version } : {}) }),});
view.setTheme('dark'); // the host's own theme switchawait view.setVersion(2); // false if the host could not mint itview.destroy();The host’s duties
Section titled “The host’s duties”- Mint with the person’s own token.
getEmbedUrlcallsPOST /api/v1/items/{id}/embedwith the signed-in person’s token, so the API checks that person’s access. Never a shared or service token. - Be allowed. The host’s origin must be in the content Worker’s
FRAME_ANCESTORSand the API’sEMBED_HOSTS, and its web client must be allowed to request the Superlibrary audience from the account service.
The toolbar
Section titled “The toolbar”| Control | What it does |
|---|---|
| Version | The version shown; a menu to switch when getVersions gives more than one |
| Files | For a folder: its files, entry first, with sizes |
| View source | For text kinds: the file as highlighted source, still sandboxed |
| Theme | System, Light or Dark, remembered on this device |
| Download | Single-file versions only |
| Full screen | The whole embed, as a modal dialog; Escape or the same button exits |
| Open in new window | The item in the Superlibrary app |
| Share | Who can see the item, in words; widening to the workspace for a person allowed to; copy the app link. There are no public links. |
Below 640 px of width, the secondary controls move into a labelled More panel. No control is an icon alone.
Options
Section titled “Options”| Option | Required | |
|---|---|---|
itemId |
yes | itm_ + 16 hex |
getEmbedUrl({ itemId, version? }) |
yes | Resolves to the API’s EmbedGrant: url, expiresAt, version, entry, files, downloadUrl, itemUrl. Called at mount, on a version switch, and again before a grant runs out. |
version |
Show this version; otherwise the newest live one | |
getVersions({ itemId }) |
Live version numbers, for the version menu | |
getShareInfo({ itemId }) |
{ scope, boardVisible?, canWiden, title? }, for the Share panel |
|
setScope({ itemId, scope: 'workspace' }) |
Widen the item, after the person confirms | |
title |
The frame’s accessible name | |
theme |
light, dark or system (default), until the person picks one |
|
appUrl |
Default https://app.superlibrary.dev |
|
height |
Initial frame height in px; default 480 | |
clipboard |
Default navigator.clipboard |
|
onVersionChange(version), onScopeChange(info) |
Callbacks for the person’s choices | |
nonce |
Put on the toolbar’s one <style> element, for a strict CSP |
Styling. Every colour is a custom property with a host hook: --sl-host-bg, -fg, -muted,
-line, -hover, -accent, -accent-content and -danger, the same names ending in -dark
for dark mode, and --sl-host-font.
The frame
Section titled “The frame”The grant’s url is https://<label>.superlibrarycontent.dev/_view?sig=<token>, on a separate
content domain with a label per item. The content Worker holds no credentials, has no API or
database, and reads storage through a type with no write methods. The URL lives five minutes; the
SDK mints a new one before it opens anything after that.
The frame is sandboxed without allow-same-origin. It talks to the host with postMessage:
| Message | Direction | |
|---|---|---|
superlibrary:resize |
frame to host | { height }, clamped to 20,000 px. HTML artifacts do not report one. |
superlibrary:theme |
host to frame | { theme }, sent on every load and theme change |
superlibrary:expired |
frame to host | A URL ran out; the SDK mints the same version again and reloads |
superlibrary:open |
frame to host | The person clicked an http(s) link; the SDK opens it in a new window |
The SDK accepts messages only from its own frame.
Allowed origins
Section titled “Allowed origins”| Setting | Where | Shipped value |
|---|---|---|
FRAME_ANCESTORS |
content Worker | https://app.superlibrary.dev https://app.superpipeline.dev https://console.agentpod.dev |
EMBED_HOSTS |
API | https://app.superpipeline.dev https://console.agentpod.dev |
EMBED_HOSTS is FRAME_ANCESTORS without the app itself; a test holds the two together.