Skip to content

App Browser SDK

The App Browser SDK is the browser-side SDK for embedded app frontends inside Lombok. An app UI runs inside an <iframe> hosted by the platform shell, and this package gives that iframe everything it needs to participate in the platform: a handshake with the parent window, an authenticated API client, navigation that stays in sync with the shell, theme propagation, a realtime socket for app events, and helpers for calling your app’s own workers.

@lombokapp/app-browser-sdk

The package targets the browser and ships React bindings. The build externalizes bun, socket.io-client, @lombokapp/auth-utils, @lombokapp/types, and @lombokapp/sdk; the remaining React/browser-facing pieces are bundled into the package output.

Your app frontend is served at a hostname like app-server--<app>.<platform_host> and embedded as an iframe by the Lombok shell. The two communicate over window.postMessage:

  1. On startup the SDK creates an IframeCommunicator and posts APP_READY to the parent.
  2. The shell replies with an AUTHENTICATION message carrying the initial tokens, theme, and path. This marks the SDK initialized.
  3. From then on the shell can push THEME_CHANGE, PARENT_NAVIGATE_TO, LOGOUT, and ERROR messages; the app can post NAVIGATE_TO back.

Because tokens arrive asynchronously via this handshake, most of the SDK is built around “wait until initialized, then act.” The React bindings hide that wait for you.

Wrap your app in the provider, then read everything through the hook:

import {
AppBrowserSdkContextProvider,
useAppBrowserSdk,
} from '@lombokapp/app-browser-sdk'
function Root() {
return (
<AppBrowserSdkContextProvider
onNavigateTo={(to) => router.push(to.pathAndQuery)}
onThemeChange={(theme) =>
(document.documentElement.dataset.theme = theme)
}
>
<App />
</AppBrowserSdkContextProvider>
)
}
function App() {
const { isInitialized, apiClient, theme, authState } = useAppBrowserSdk()
if (!isInitialized) return <Splash />
return <Dashboard />
}
ExportKindPurpose
AppBrowserSdkContextProviderReact componentInstantiates and owns a single AppBrowserSdk, exposes it via context.
useAppBrowserSdkReact hookReads the SDK context (ISdkContext). Throws if no provider is mounted.
ISdkContexttypeShape of the value returned by useAppBrowserSdk.
SdkContextReact contextThe underlying context object.
AppUserSocketProviderReact componentOpens a shared authenticated /app-user socket for the current app + user.
useAppUserSocketReact hookAccess the raw socket, connection state, and subscribe.
useAppUserSocketEventReact hookSubscribe to a single raw socket.io event by name.
useAppEventReact hookSubscribe to a custom app event (app:<app>:<event>) by app + event identifier.
AppEventPayloadtypePayload shape for custom app events emitted from a worker.
LinkReact componentNavigates within the shell via the SDK instead of a hard browser nav.
createBridgeConnectionfunctionOpen a direct WebSocket to the Docker bridge.
BridgeConnection / BridgeConnectionOptions / BridgeSessionCredentialstypesBridge connection contract.
IframeMessagetypeEnvelope for messages exchanged with the parent window.
TokenDatatypeRe-export of InitialData: the auth/theme/path payload from the shell.

The core class implements AppBrowserSdkInstance and holds most of its lifecycle state on static fields, so a single iframe shares one initialization regardless of how many instances are created.

interface AppBrowserSdkConfig {
onInitialize?: () => void
onNavigateTo?: (to: { pathAndQuery: string }) => void
onThemeChange?: (theme: string) => void
}

| Member | Type | Description | | ------------------- | ----------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | sdk | LombokSdk | The underlying core SDK, wired to a token store backed by the iframe handshake. | | apiClient | typed API client | Typed API client (sdk.apiClient). | | authenticator | Authenticator | Auth controller (sdk.authenticator). | | communicator | Promise<IframeCommunicator> | Resolves once initialized; lazily creates the communicator and sends APP_READY. | | isInitialized | boolean | Whether the AUTHENTICATION handshake has completed. | | theme | string | Current theme. | | initialData | InitialData | undefined | The accessToken/refreshToken/pathAndQuery/theme delivered by the shell. | | lombokApiBasePath | string | Platform API origin, derived from the iframe hostname. | | appIdentifier | string | App id parsed from the app-server--<app> hostname label. |

  • waitForInitialized()
  • handleNavigateTo()
  • executeWorkerScriptUrl()
  • destroy()

Calling app workers — executeWorkerScriptUrl

Section titled “Calling app workers — executeWorkerScriptUrl”

Issues an authenticated fetch to one of your app’s workers. The worker is addressed cross-origin at api-server--<worker>--<app>.<platform_host> and the current app-user access token is attached as a bearer token.

const res = await sdk.executeWorkerScriptUrl(
{ workerIdentifier: 'my-worker', url: '/do-thing' },
{ method: 'POST', body: JSON.stringify({ ... }) },
)

Creates exactly one AppBrowserSdk for its subtree and exposes it via context. Props mirror AppBrowserSdkConfig.

Returns the context value. Throws if no provider is mounted.

interface ISdkContext {
isInitialized: boolean
apiClient: AppBrowserSdk['apiClient']
theme: string
authState: Authenticator['state']
navigateTo: (to: { pathAndQuery: string }) => Promise<void>
lombokApiBasePath: string
appIdentifier: string
currentPathAndQuery: string
getAccessToken: () => Promise<string | undefined>
executeWorkerScriptUrl: AppBrowserSdk['executeWorkerScriptUrl']
}

A lightweight in-shell navigation element. Instead of a real anchor it routes through navigateTo, keeping the parent shell URL in sync.

The app-user socket delivers custom events your workers emit toward a specific user, fanned out to that user’s open tabs.

Opens a single authenticated socket.io connection on the /app-user namespace once the SDK is initialized and the user is authenticated.

  • useAppUserSocket()
  • useAppUserSocketEvent(eventName, handler)
  • useAppEvent(appIdentifier, eventIdentifier, handler)

For features that need a direct, low-latency channel to the Docker bridge, createBridgeConnection opens a WebSocket straight to the bridge using session-scoped credentials.

import { createBridgeConnection } from '@lombokapp/app-browser-sdk'
const conn = await createBridgeConnection({
credentials,
onData: (bytes) => term.write(bytes),
onClose: () => term.dispose(),
onError: (msg) => console.error(msg),
})

IframeCommunicator wraps window.postMessage. It only accepts messages whose event.source is the parent window and dispatches by message.type.

Message types in use include:

  • APP_READY
  • APP_ERROR
  • NAVIGATE_TO
  • AUTHENTICATION
  • THEME_CHANGE
  • PARENT_NAVIGATE_TO
  • LOGOUT
  • ERROR
interface InitialData {
accessToken: string
refreshToken: string
pathAndQuery: string
theme: string
}
interface AppBrowserSdkInstance {
sdk: LombokSdk
communicator: Promise<IframeCommunicator>
apiClient: AppBrowserSdk['apiClient']
authenticator: Authenticator
destroy: () => void
}