The SDK & bridge
The SDK & postMessage bridge
How your app talks to the workspace host — the postMessage protocol, scoped tokens, and file access via the Verentis SDK.
Your app runs in a sandboxed iframe, isolated from the workspace host. The Verentis SDK
(@verentis/sdk) connects the two over a postMessage protocol so your app can receive launch
context and call platform APIs with a short-lived token — without ever handling raw credentials.
The bridge in one picture
┌─────────────────────────────┐ postMessage ┌──────────────────────┐
│ Workspace host (parent) │ ◄────────────────────────► │ Your app (iframe) │
│ • injects scoped tokens │ init / events │ • @verentis/sdk │
│ • owns workspace routing │ │ • view / edit UI │
└─────────────────────────────┘ └──────────────────────┘
The host is the trusted broker. It holds the user session, mints short-lived tokens, and validates each request against the permissions the workspace consented to for your app.
Initialising the SDK
Connect to the host when your app loads:
import { createVerentisClient } from '@verentis/sdk'
const client = createVerentisClient()
await client.whenReady()
const { surface, workspace, entryPoint } = client.context
Tokens are injected, not stored
You never embed a client secret or API key in an iframe app. The host injects and refreshes a short-lived token containing the manifest permissions granted to the app. SDK modules use that token automatically.
File and workspace launch context
The context is a discriminated union:
if (client.context.surface === 'file') {
const file = client.context.file
const content = await client.files.readContent(file.path)
} else {
// A spec.launch app opened without a selected file.
// client.context.file is unavailable on this surface.
renderWorkspaceHome(client.context.workspace)
}
| Context property | File launch | spec.launch workspace launch |
|---|---|---|
surface | 'file' | 'workspace' |
workspace | Present | Present |
file / hasFile | File metadata / true | Throws if read / false |
entryPoint | Matched file-handler entry point | Configured launch entry point (or default) |
apiUrl | Present | Present |
Older hosts sent file context without surface; the SDK treats that legacy shape as file.
Two meanings of standalone
Manifest spec.launch still runs inside the workspace iframe and receives
surface: 'workspace'. SDK “standalone mode” means running outside any iframe with explicit
apiUrl, credentials and workspaceId; it is a separate local-development mode.
Reading and writing files
Use VFS paths with the SDK:
const content = await client.files.readContent('/reports/q1.json')
await client.files.write('/reports/q1.json', {
content: updatedJson,
contentType: 'application/json',
})
These calls go through the platform file/node APIs with the injected token. Declare the corresponding permissions in the manifest; see Working with files & nodes.
Host navigation
Ask the host to navigate instead of assigning the parent window:
client.bridge?.navigate('/reports/q1.json')
client.bridge?.navigate('/reports/q1.json', { newTab: true })
client.bridge?.navigate('https://docs.example.com', { newTab: true })
A VFS path is converted to /files/** by the host. /files/** is also accepted, but old root-level
browser URLs are not redirected. Absolute HTTP(S) targets require the
navigation:external capability; other schemes and protocol-relative URLs are rejected.
Responsive iframe surfaces
The workspace uses a persistent sidebar on large screens and a navigation drawer on smaller screens. Notifications, the inspector and the assistant open as overlay panels. Your iframe therefore changes size without a page reload.
Build against the iframe's available width rather than 100vw, use fluid breakpoints, and test both
file and workspace launch surfaces. client.bridge?.resize(height) is available for
intrinsic-height content; a full-height application should normally fill the host-provided container.
Standalone development
While iterating outside the platform, create the client with an API URL, API key or bearer token, and
workspace ID. whenReady() resolves immediately and bridge is null:
const client = createVerentisClient({
apiUrl: 'https://api.localtest.me:6500',
auth: { apiKey: 'vrt_...' },
workspaceId: 'workspace-uuid',
})
Language SDKs for engines
Execution engines use the same pattern with a language-appropriate SDK (e.g. Python) inside the runtime. The shape of the API — context, scoped token, file read/write — mirrors the TypeScript SDK. See The execution model.
Next
How your app's OAuth client and scopes are approved on install.