Skip to content

API Reference

PortableInventory Class

The main SDK class. Manages an iframe-based widget with typed event communication.

Constructor

new PortableInventory(config: PortableInventoryConfig)

Throws if apiKey or container is missing.

PortableInventoryConfig

Property Type Required Default Description
apiKey string Yes — API key for authenticating with the widget backend
baseUrl string No window.location.origin Base URL of the Varasto instance
container string \| HTMLElement Yes — CSS selector or DOM element to mount the widget into
theme ThemeConfig No DEFAULT_THEME Visual theme configuration
locale string No — Locale code (e.g. en, fr) passed to the widget

Static methods

PortableInventory.exchangeToken(token: string, baseUrl?: string): Promise<string>

Exchanges a short-lived QR token for the company API key. QR redirects (/go/<code>/) emit a signed, expiring ?token=... instead of embedding the long-lived key in the URL. Call this once to resolve the key, then construct the widget with it. Tokens expire after ~10 minutes; on expiry the promise rejects and the user must re-scan.

const params = new URLSearchParams(window.location.search);
const token = params.get("token");

const apiKey = token
  ? await PortableInventory.exchangeToken(token)
  : params.get("api_key"); // legacy fallback (deprecated)

const widget = new PortableInventory({ apiKey, container: "#widget" });
widget.mount();

Embedding api_key directly in a QR URL is deprecated — use the token flow. See the Widget API authentication section.

Methods

mount(): void

Creates an iframe targeting the widget route and inserts it into the container. Sets up the postMessage listener for cross-origin communication. Idempotent — calling mount() on an already-mounted widget is a no-op.

Throws if the container selector does not match any DOM element.

widget.mount();

unmount(): void

Removes the iframe from the DOM and cleans up the message listener. Safe to call when not mounted. The instance remains reusable — you can call mount() again after unmounting.

widget.unmount();

destroy(): void

Calls unmount(), then clears all registered event listeners and nullifies the container reference. The instance is no longer usable after destroy().

widget.destroy();

on<T extends WidgetEventType>(event: T, callback: (data: WidgetEventMap[T]) => void): void

Registers a typed event listener. Multiple listeners can be registered for the same event.

widget.on('ready', (data) => {
  // data is typed as { version: string; capabilities: string[] }
  console.log(data.version);
});

off<T extends WidgetEventType>(event: T, callback: (data: WidgetEventMap[T]) => void): void

Removes a previously registered event listener. Pass the same function reference used in on(). Safe to call if the listener was never registered.

const handler = (data) => console.log(data);
widget.on('transaction_complete', handler);
widget.off('transaction_complete', handler);

setProduct(productId: string | number): void

Sends a HOST_COMMAND message to the widget to navigate to the specified product. Does not throw if the iframe is not yet mounted.

widget.setProduct(42);

setLocation(locationId: string | number): void

Sends a HOST_COMMAND message to the widget to set the active location context. Does not throw if the iframe is not yet mounted.

widget.setLocation(7);

ThemeConfig

Controls the visual appearance of the embedded widget. All properties are optional — omitted values fall back to DEFAULT_THEME.

Property Type Default Description
primaryColor string '#3b82f6' Primary accent color (buttons, links, highlights)
backgroundColor string '#ffffff' Widget background color
textColor string '#1f2937' Primary text color
borderRadius string '8px' Border radius for cards and inputs
fontFamily string 'system-ui, -apple-system, sans-serif' Font stack
compact boolean false Reduces padding and font sizes for tighter layouts

Themes are serialized as base64-encoded JSON and passed to the widget iframe via query parameter. Inside the widget, values are applied as CSS custom properties:

CSS Variable Maps to
--pi-primary primaryColor
--pi-bg backgroundColor
--pi-text textColor
--pi-radius borderRadius
--pi-font fontFamily

Theme Utility Functions

import { serializeTheme, deserializeTheme, DEFAULT_THEME } from '@portable-inventory/widget-sdk';

serializeTheme(theme: ThemeConfig): string

Merges the provided theme with DEFAULT_THEME and returns a base64-encoded JSON string suitable for URL parameters.

deserializeTheme(encoded: string): ThemeConfig

Decodes a base64 theme string back to a ThemeConfig object. Returns DEFAULT_THEME on parse failure.

DEFAULT_THEME

{
  primaryColor: '#3b82f6',
  backgroundColor: '#ffffff',
  textColor: '#1f2937',
  borderRadius: '8px',
  fontFamily: 'system-ui, -apple-system, sans-serif',
  compact: false,
}

Events

WidgetEventType

type WidgetEventType = 'ready' | 'resize' | 'transaction_complete' | 'error'

WidgetEventMap

Event Payload When
ready { version: string; capabilities: string[] } Widget iframe loaded and initialized
resize { height: number } Widget content height changed (iframe auto-resizes)
transaction_complete { transactionType: string; productId: string \| number; quantity: number; success: boolean } Inventory operation completed
error { message: string; code?: string } An error occurred inside the widget

Example: Full Event Handling

const widget = new PortableInventory({
  apiKey: 'your-api-key',
  container: '#widget',
});

widget.on('ready', ({ version, capabilities }) => {
  console.log(`Widget v${version} ready. Capabilities:`, capabilities);
});

widget.on('resize', ({ height }) => {
  console.log(`Widget resized to ${height}px`);
});

widget.on('transaction_complete', ({ transactionType, productId, quantity, success }) => {
  if (success) {
    showToast(`${transactionType}: ${quantity}x product #${productId}`);
  }
});

widget.on('error', ({ message, code }) => {
  console.error(`Widget error [${code}]: ${message}`);
});

widget.mount();

PostMessage Protocol

The SDK communicates with the widget iframe using window.postMessage. All messages follow this envelope:

interface PostMessagePayload {
  type: 'WIDGET_READY' | 'WIDGET_RESIZE' | 'WIDGET_EVENT' | 'HOST_COMMAND'
  source: 'portable-inventory-widget' | 'portable-inventory-host'
  payload: Record<string, unknown>
}
Type Direction Description
WIDGET_READY Widget -> Host Emitted on widget load with version and capabilities
WIDGET_RESIZE Widget -> Host Reports content height for iframe auto-sizing
WIDGET_EVENT Widget -> Host Carries typed events (transaction_complete, error)
HOST_COMMAND Host -> Widget Sends commands (setProduct, setLocation, setTheme)

See Security for origin validation details.


TypeScript Exports

All public types are exported from the package entry point:

import {
  PortableInventory,
  PortableInventoryElement,   // Web Component class
  serializeTheme,
  deserializeTheme,
  DEFAULT_THEME,
} from '@portable-inventory/widget-sdk';

import type {
  PortableInventoryConfig,
  ThemeConfig,
  WidgetEvent,
  WidgetEventMap,
  PostMessagePayload,
} from '@portable-inventory/widget-sdk';