0
# Superset UI Switchboard
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: @superset-ui/switchboard
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @superset-ui/switchboard`
10
11
## Core Imports
12
13
```typescript
14
import { Switchboard, type Params } from "@superset-ui/switchboard";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { Switchboard } = require("@superset-ui/switchboard");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { Switchboard } from "@superset-ui/switchboard";
27
28
// Create MessageChannel for communication
29
const channel = new MessageChannel();
30
31
// Parent window switchboard
32
const parentBoard = new Switchboard({
33
port: channel.port1,
34
name: 'parent',
35
debug: true
36
});
37
38
// Child window switchboard (inside iframe)
39
const childBoard = new Switchboard({
40
port: channel.port2,
41
name: 'child'
42
});
43
44
// Define method on child side
45
childBoard.defineMethod('getData', (args) => {
46
return { data: 'hello', timestamp: Date.now() };
47
});
48
49
// Start listening
50
childBoard.start();
51
52
// Call method from parent side
53
const result = await parentBoard.get('getData', { query: 'users' });
54
console.log(result); // { data: 'hello', timestamp: 1638360000000 }
55
56
// Fire-and-forget call
57
parentBoard.emit('logEvent', { event: 'user_action' });
58
```
59
60
## Architecture
61
62
Switchboard is built around the MessageChannel API and provides:
63
64
- **Method Registration**: Define callable methods on either side of the communication channel
65
- **Synchronous Calls**: `get()` method calls with Promise-based responses
66
- **Asynchronous Calls**: `emit()` method calls without waiting for responses
67
- **Error Handling**: Built-in error catching and messaging for failed method calls
68
- **Message Identification**: Unique message IDs to match requests with responses
69
- **Debug Support**: Optional logging for troubleshooting communication issues
70
71
## Capabilities
72
73
### Switchboard Class
74
75
Main class for managing iframe-parent window communication using MessageChannel.
76
77
```typescript { .api }
78
/**
79
* A utility for communications between an iframe and its parent, used by the Superset embedded SDK.
80
* This builds useful patterns on top of the basic functionality offered by MessageChannel.
81
*/
82
class Switchboard {
83
/** The MessagePort used for communication */
84
port: MessagePort;
85
/** Instance name for debugging */
86
name: string;
87
/** Registry of callable methods */
88
methods: Record<string, Method<any, unknown>>;
89
/** Internal message ID counter */
90
incrementor: number;
91
/** Debug mode flag */
92
debugMode: boolean;
93
94
constructor(params: Params);
95
}
96
```
97
98
### Constructor
99
100
Creates a new Switchboard instance with the specified configuration.
101
102
```typescript { .api }
103
/**
104
* Creates a new Switchboard instance
105
* @param params - Configuration parameters
106
*/
107
constructor(params: Params);
108
```
109
110
### Method Registration
111
112
Defines a method that can be called from the other side of the communication channel.
113
114
```typescript { .api }
115
/**
116
* Defines a method that can be "called" from the other side by sending an event
117
* @param methodName - Name of the method to register
118
* @param executor - Function to execute when method is called
119
*/
120
defineMethod<A = any, R = any>(methodName: string, executor: Method<A, R>): void;
121
```
122
123
**Usage Example:**
124
125
```typescript
126
switchboard.defineMethod('authenticate', async (credentials) => {
127
const { username, password } = credentials;
128
const token = await authenticateUser(username, password);
129
return { token, userId: 123, expires: Date.now() + 3600000 };
130
});
131
```
132
133
### Synchronous Method Calls
134
135
Calls a method registered on the other side and returns the result via Promise.
136
137
```typescript { .api }
138
/**
139
* Calls a method registered on the other side, and returns the result.
140
* Sends a "get" message, waits for a "reply" message with the result.
141
*
142
* @param method - Name of the method to call
143
* @param args - Arguments to pass (must be serializable)
144
* @returns Promise resolving to the method's return value
145
* @throws Error if method not found or execution fails
146
*/
147
get<T = unknown>(method: string, args?: unknown): Promise<T>;
148
```
149
150
**Usage Example:**
151
152
```typescript
153
// Call a method and wait for response
154
try {
155
const userData = await switchboard.get('fetchUserData', { userId: 123 });
156
console.log('User:', userData.name);
157
} catch (error) {
158
console.error('Failed to fetch user data:', error.message);
159
}
160
```
161
162
### Asynchronous Method Calls
163
164
Calls a method on the other side without waiting for a response (fire-and-forget).
165
166
```typescript { .api }
167
/**
168
* Emit calls a method on the other side just like get does.
169
* But emit doesn't wait for a response, it just sends and forgets.
170
*
171
* @param method - Name of the method to call
172
* @param args - Arguments to pass (must be serializable)
173
*/
174
emit(method: string, args?: unknown): void;
175
```
176
177
**Usage Example:**
178
179
```typescript
180
// Fire-and-forget method call
181
switchboard.emit('trackEvent', {
182
event: 'dashboard_viewed',
183
dashboardId: 456,
184
timestamp: Date.now()
185
});
186
```
187
188
### Start Communication
189
190
Starts the MessagePort to begin listening for messages.
191
192
```typescript { .api }
193
/**
194
* Starts the MessagePort to begin listening for messages
195
*/
196
start(): void;
197
```
198
199
## Types
200
201
### Params Interface
202
203
Configuration parameters for Switchboard constructor.
204
205
```typescript { .api }
206
/**
207
* Configuration parameters for Switchboard constructor
208
*/
209
interface Params {
210
/** MessagePort for communication (required) */
211
port: MessagePort;
212
/** Name for debugging purposes (default: 'switchboard') */
213
name?: string;
214
/** Enable debug logging (default: false) */
215
debug?: boolean;
216
}
217
```
218
219
### Method Type
220
221
Function signature for methods that can be registered with defineMethod.
222
223
```typescript { .api }
224
/**
225
* Function signature for methods that can be registered with defineMethod
226
* @template A - Type of arguments object
227
* @template R - Return type
228
*/
229
type Method<A extends {}, R> = (args: A) => R | Promise<R>;
230
```
231
232
## Error Handling
233
234
Switchboard provides built-in error handling for method calls:
235
236
- **Method Not Found**: If a called method doesn't exist, the Promise rejects with a descriptive error
237
- **Execution Errors**: If a method throws an error during execution, it's caught and returned as an error message
238
- **Serialization**: Only serializable data can be passed as arguments or return values (no functions, DOM nodes, etc.)
239
240
**Error Handling Example:**
241
242
```typescript
243
try {
244
const result = await switchboard.get('nonexistentMethod');
245
} catch (error) {
246
// Error message will be: "[switchboard_name] Method "nonexistentMethod" is not defined"
247
console.error('Method call failed:', error.message);
248
}
249
```
250
251
## Communication Flow
252
253
1. **Setup**: Both sides create Switchboard instances with their respective MessagePorts
254
2. **Method Registration**: Each side registers methods using `defineMethod()`
255
3. **Start Listening**: Call `start()` to begin processing messages
256
4. **Method Calls**: Use `get()` for responses or `emit()` for fire-and-forget calls
257
5. **Message Processing**: Switchboard handles message routing, method execution, and response delivery
258
259
## Common Use Cases
260
261
- **Embedded Dashboards**: Communication between Superset dashboards and parent applications
262
- **Authentication**: Passing authentication tokens between iframe and parent
263
- **Configuration**: Sending configuration updates from parent to iframe
264
- **Event Tracking**: Sending analytics events from iframe to parent
265
- **Data Exchange**: Requesting and sharing data between contexts while maintaining security boundaries