Xeonr Developer Docs
Custom Renderers

Renderer SDK

API reference for @xeonr/renderer-sdk — the client library for building custom renderers.

The @xeonr/renderer-sdk package provides everything your renderer needs to communicate with the host.

React hook: useRendererClient

This is the recommended way to use the SDK in React applications.

import { useRendererClient } from '@xeonr/renderer-sdk/react';

const {
  // State
  connected,      // boolean — true after the host sends init
  scope,          // RendererScope | null
  renderingType,  // RenderingType | null
  theme,          // 'light' | 'dark'
  token,          // string | null — current access token
  tokenExpiresAt, // number | null — Unix timestamp (ms)
  entrypoint,     // 'dashboard' | 'portal' | null
  apiBaseUrl,     // string | null
  config,         // RendererConfig | null
  apiAdapter,     // RendererApiAdapter — pre-configured for API clients

  // Methods
  openUpload,     // (uploadId: string) => void
  requestToken,   // () => void
  generateToken,  // (opts: { reason: string; duration: string }) => Promise<{ accepted: boolean }>
  close,          // () => void

  // Advanced
  client,         // RendererClient instance
} = useRendererClient();

The hook automatically:

  • Initialises the RendererClient and manages its lifecycle
  • Sets document.documentElement.dataset.theme when the theme changes
  • Provides stable, memoised method references

Vanilla JS: RendererClient

For non-React applications, use the client directly:

import { RendererClient } from '@xeonr/renderer-sdk';

const client = new RendererClient();

client.onInit((payload) => {
  // Bootstrap your app with payload.scope, payload.theme, etc.
});

client.onThemeChange((theme) => {
  // Update your theme
});

client.onTokenRefresh((token, expiresAt) => {
  // Store the refreshed token
});

// Request actions from the host
client.openUpload('upl_abc123');
client.close();

// Get a fresh token (async)
const { token, expiresAt } = await client.requestTokenAsync();

// Prompt the user to generate a long-lived token
const { accepted } = await client.generateToken({
  reason: 'CLI access for publishing packages',
  duration: '30d', // or 'forever'
});

API adapter

The apiAdapter returned by the hook (or via client.getApiAdapter()) is pre-configured with authentication and automatic token refresh. Pass it to @xeonr/uploads-sdk to make authenticated API calls:

import { getUploadClientWithEnv } from '@xeonr/uploads-sdk/api/base';
import { BucketUploadsService } from '@xeonr/uploads-protocol/uplim/api/v1/uploads_pb';

const client = getUploadClientWithEnv(BucketUploadsService, apiAdapter);
const res = await client.getUpload({
  bucketRef: { type: { case: 'bucketId', value: scope.bucketId } },
  uploadRef: { type: { case: 'uploadId', value: scope.uploadId } },
});

Generating long-lived tokens

Renderers can prompt the user to generate a long-lived access token scoped to the integration. This is useful for CLI tools, CI/CD pipelines, or other external systems that need persistent API access.

const { accepted } = await client.generateToken({
  reason: 'CLI access for publishing packages',
  duration: '30d',
});

When called, the host displays a modal to the user showing:

  • The integration name
  • The reason provided by the renderer
  • The requested duration

If the user accepts, an OAuth consent flow runs in a popup, and the resulting token is displayed to the user with a copy button. The token is never returned to the renderer — the renderer only learns whether the user accepted or rejected the request.

Parameters

FieldTypeDescription
reasonstringDisplayed to the user explaining why the token is needed
durationstringToken lifetime: 'forever' for non-expiring, or a duration string like '30d', '1y', '12h'

Duration format

UnitSuffixExample
Secondss'3600s'
Minutesm'60m'
Hoursh'12h'
Daysd'30d'
Weeksw'4w'
Yearsy'1y'

Use 'forever' for tokens with no expiry.

Return value

The promise resolves with { accepted: true } if the user completed the flow, or { accepted: false } if they rejected it. The promise never rejects under normal circumstances (only if the client is destroyed while the request is pending).

Security model

  • The renderer cannot see or access the generated token
  • The user must explicitly approve via an OAuth consent popup
  • Custom durations are capped by the auth server (max 365 days for non-forever tokens)
  • forever tokens require the auth:forever scope to be granted during consent

On this page