or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-superset-ui--switchboard

Switchboard is a library to make it easier to communicate across browser windows using the MessageChannel API

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@superset-ui/switchboard@0.18.x

To install, run

npx @tessl/cli install tessl/npm-superset-ui--switchboard@0.18.0

index.mddocs/

Superset UI Switchboard

Switchboard is a TypeScript library that provides secure communication between iframe windows and their parent windows using the MessageChannel API. It enables structured method calls across window boundaries with support for both synchronous (get) and asynchronous (emit) patterns, specifically designed for the Superset embedded SDK.

Package Information

  • Package Name: @superset-ui/switchboard
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @superset-ui/switchboard

Core Imports

import { Switchboard, type Params } from "@superset-ui/switchboard";

For CommonJS:

const { Switchboard } = require("@superset-ui/switchboard");

Basic Usage

import { Switchboard } from "@superset-ui/switchboard";

// Create MessageChannel for communication
const channel = new MessageChannel();

// Parent window switchboard
const parentBoard = new Switchboard({ 
  port: channel.port1, 
  name: 'parent',
  debug: true 
});

// Child window switchboard (inside iframe)
const childBoard = new Switchboard({ 
  port: channel.port2, 
  name: 'child' 
});

// Define method on child side
childBoard.defineMethod('getData', (args) => {
  return { data: 'hello', timestamp: Date.now() };
});

// Start listening
childBoard.start();

// Call method from parent side
const result = await parentBoard.get('getData', { query: 'users' });
console.log(result); // { data: 'hello', timestamp: 1638360000000 }

// Fire-and-forget call
parentBoard.emit('logEvent', { event: 'user_action' });

Architecture

Switchboard is built around the MessageChannel API and provides:

  • Method Registration: Define callable methods on either side of the communication channel
  • Synchronous Calls: get() method calls with Promise-based responses
  • Asynchronous Calls: emit() method calls without waiting for responses
  • Error Handling: Built-in error catching and messaging for failed method calls
  • Message Identification: Unique message IDs to match requests with responses
  • Debug Support: Optional logging for troubleshooting communication issues

Capabilities

Switchboard Class

Main class for managing iframe-parent window communication using MessageChannel.

/**
 * A utility for communications between an iframe and its parent, used by the Superset embedded SDK.
 * This builds useful patterns on top of the basic functionality offered by MessageChannel.
 */
class Switchboard {
  /** The MessagePort used for communication */
  port: MessagePort;
  /** Instance name for debugging */
  name: string;
  /** Registry of callable methods */
  methods: Record<string, Method<any, unknown>>;
  /** Internal message ID counter */
  incrementor: number;
  /** Debug mode flag */
  debugMode: boolean;

  constructor(params: Params);
}

Constructor

Creates a new Switchboard instance with the specified configuration.

/**
 * Creates a new Switchboard instance
 * @param params - Configuration parameters
 */
constructor(params: Params);

Method Registration

Defines a method that can be called from the other side of the communication channel.

/**
 * Defines a method that can be "called" from the other side by sending an event
 * @param methodName - Name of the method to register
 * @param executor - Function to execute when method is called
 */
defineMethod<A = any, R = any>(methodName: string, executor: Method<A, R>): void;

Usage Example:

switchboard.defineMethod('authenticate', async (credentials) => {
  const { username, password } = credentials;
  const token = await authenticateUser(username, password);
  return { token, userId: 123, expires: Date.now() + 3600000 };
});

Synchronous Method Calls

Calls a method registered on the other side and returns the result via Promise.

/**
 * Calls a method registered on the other side, and returns the result.
 * Sends a "get" message, waits for a "reply" message with the result.
 * 
 * @param method - Name of the method to call
 * @param args - Arguments to pass (must be serializable)
 * @returns Promise resolving to the method's return value
 * @throws Error if method not found or execution fails
 */
get<T = unknown>(method: string, args?: unknown): Promise<T>;

Usage Example:

// Call a method and wait for response
try {
  const userData = await switchboard.get('fetchUserData', { userId: 123 });
  console.log('User:', userData.name);
} catch (error) {
  console.error('Failed to fetch user data:', error.message);
}

Asynchronous Method Calls

Calls a method on the other side without waiting for a response (fire-and-forget).

/**
 * Emit calls a method on the other side just like get does.
 * But emit doesn't wait for a response, it just sends and forgets.
 * 
 * @param method - Name of the method to call
 * @param args - Arguments to pass (must be serializable)
 */
emit(method: string, args?: unknown): void;

Usage Example:

// Fire-and-forget method call
switchboard.emit('trackEvent', { 
  event: 'dashboard_viewed', 
  dashboardId: 456,
  timestamp: Date.now() 
});

Start Communication

Starts the MessagePort to begin listening for messages.

/**
 * Starts the MessagePort to begin listening for messages
 */
start(): void;

Types

Params Interface

Configuration parameters for Switchboard constructor.

/**
 * Configuration parameters for Switchboard constructor
 */
interface Params {
  /** MessagePort for communication (required) */
  port: MessagePort;
  /** Name for debugging purposes (default: 'switchboard') */
  name?: string;
  /** Enable debug logging (default: false) */
  debug?: boolean;
}

Method Type

Function signature for methods that can be registered with defineMethod.

/**
 * Function signature for methods that can be registered with defineMethod
 * @template A - Type of arguments object
 * @template R - Return type
 */
type Method<A extends {}, R> = (args: A) => R | Promise<R>;

Error Handling

Switchboard provides built-in error handling for method calls:

  • Method Not Found: If a called method doesn't exist, the Promise rejects with a descriptive error
  • Execution Errors: If a method throws an error during execution, it's caught and returned as an error message
  • Serialization: Only serializable data can be passed as arguments or return values (no functions, DOM nodes, etc.)

Error Handling Example:

try {
  const result = await switchboard.get('nonexistentMethod');
} catch (error) {
  // Error message will be: "[switchboard_name] Method "nonexistentMethod" is not defined"
  console.error('Method call failed:', error.message);
}

Communication Flow

  1. Setup: Both sides create Switchboard instances with their respective MessagePorts
  2. Method Registration: Each side registers methods using defineMethod()
  3. Start Listening: Call start() to begin processing messages
  4. Method Calls: Use get() for responses or emit() for fire-and-forget calls
  5. Message Processing: Switchboard handles message routing, method execution, and response delivery

Common Use Cases

  • Embedded Dashboards: Communication between Superset dashboards and parent applications
  • Authentication: Passing authentication tokens between iframe and parent
  • Configuration: Sending configuration updates from parent to iframe
  • Event Tracking: Sending analytics events from iframe to parent
  • Data Exchange: Requesting and sharing data between contexts while maintaining security boundaries