Verentis

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 propertyFile launchspec.launch workspace launch
surface'file''workspace'
workspacePresentPresent
file / hasFileFile metadata / trueThrows if read / false
entryPointMatched file-handler entry pointConfigured launch entry point (or default)
apiUrlPresentPresent

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

Installation & consent

How your app's OAuth client and scopes are approved on install.