forma-embedded-view-sdk
Version:
The Forma Embedded View SDK is a JavaScript library for creating custom extensions in Autodesk Forma (previously Spacemaker).
180 lines (179 loc) • 6.71 kB
TypeScript
import type { EventHandler, RequestHandler, SubscribeHandler } from "./types.js";
/**
* Structured error that can be used for errors on requests,
* such as data validation errors.
*
* A handler can throw this error and it will properly be serialized
* as part of the reply and deserialized on the other side. This allows
* to return errors with additional context as a low-level primitive.
*/
export declare class RequestError extends Error {
type: string;
data: unknown;
constructor(message: string, type: string, data: unknown, options?: {
cause?: unknown;
});
}
declare const messageTypeRequest = "IFRAME-MESSAGE-REQUEST";
declare const messageTypeResponse = "IFRAME-MESSAGE-RESPONSE";
declare const messageTypeEvent = "IFRAME-MESSAGE-EVENT";
/**
* @hidden
* @internal
*/
export type IframeMessageEvent = {
type: typeof messageTypeEvent;
action: string;
payload: unknown;
};
/**
* @hidden
* @internal
*/
export type IframeMessageRequest = {
/**
* The ID is a unique identifier used to connect
* the response message to the proper request.
*/
id: string;
type: typeof messageTypeRequest;
action: string;
payload: unknown;
};
/**
* @hidden
* @internal
*/
export type IframeMessageResponse = {
/**
* The ID is a unique identifier used to connect
* the response message to the proper request.
*/
id: string;
type: typeof messageTypeResponse;
payload: unknown;
error?: boolean | undefined;
};
/**
* @hidden
* @internal
*/
export type CreateSubscriptionResult = {
unsubscribe: () => void;
};
/**
* @hidden
* @internal
*/
export type IframeMessengerOptions = {
source: Window;
/**
* The origin where messages are expected from and that we will
* use as destination for outgoing messages.
*
* Set to undefined if not checking origin in incoming messages
* and sending outgoing messages to "*".
*
* Do not use undefined in the configuration side of an iframe if
* sending sensitive data such as credentials.
*/
sourceOrigin?: string | undefined;
requestResolver?: ((action: string) => RequestHandler | undefined) | undefined;
eventResolver?: ((action: string) => EventHandler | undefined) | undefined;
subscribeResolver?: ((name: string) => SubscribeHandler | undefined) | undefined;
debug?: boolean | undefined;
/**
* A function that optionally returns a function that can be used to
* intercept incoming postMessage messages, before they are passed
* to the relevant handlers. This can be used to transform the incoming data.
*/
incomingMessageInterceptorResolver?: (() => ((message: unknown) => unknown) | undefined) | undefined;
/**
* A function that optionally returns a function that can be used to
* intercept outgoing postMessage messages, before they are sent using
* postMessage. This can be used to transform the outgoing data.
*/
outgoingMessageInterceptorResolver?: (() => ((message: unknown, options: {
request?: IframeMessageRequest | undefined;
}) => unknown) | undefined) | undefined;
};
type DeregisterFn = () => void;
/**
* IframeMessenger handles communication in/out of an iframe.
*
* It creates an abstraction on top of the Window.postMessage() browser
* API to make it more convenient to handle states, message passing
* and routing messages to handlers.
*
* Functionality provided:
*
* - Sending requests and waiting for the response for it. Think of it
* as a way of doing async functions across browser windows. Since the
* cross-window communcation is async itself, there is no support for
* synchronous requests.
*
* - Sending events to the other window. Events are one-way messages that
* do not expect a reply. Use cases for this is rare, and in most
* cases solved by subscriptions instead.
*
* - Subscriptions. This is a way to subscribe to specific events from the
* other window. The window that exposes a subscription source will contain
* a handler that can emit events for it when the subscription is created.
* This allows for lazy event streams that are only created when needed.
*
* Internally subscriptions are built on top of both requests (creating and
* deleting subscriptions) and events mentioned above.
*
* Subscriptions are unsubscribed automatically on disconnect.
*
* - Connected callbacks. This allows to add logic that should happen
* as soon as the connection between the windows are established.
*
* By default messages are queued until the connection is established,
* so the user does not have to be concerned about connection details.
*
* When an iframe is removed from DOM, the connection should be explicitly
* disconnected by calling disconnect() to trigger proper cleanup.
*
* @hidden
* @internal
*/
export declare class IframeMessenger {
#private;
debug: boolean;
source: Window;
sourceOrigin: string | undefined;
incomingMessageInterceptorResolver: (() => ((message: unknown) => unknown) | undefined) | undefined;
outgoingMessageInterceptorResolver: (() => ((message: unknown, options: {
request?: IframeMessageRequest | undefined;
}) => unknown) | undefined) | undefined;
requestResolver: ((action: string) => RequestHandler | undefined) | undefined;
eventResolver: ((action: string) => EventHandler | undefined) | undefined;
subscribeResolver: ((name: string) => SubscribeHandler | undefined) | undefined;
constructor(options: IframeMessengerOptions);
connect(): void;
disconnect(): void;
/**
* Subscribe to state transitions for being connected and
* from being connected to disconnected.
*
* This essentially acts as a boolean flag if it is connected
* or not.
*/
onStateChange(handler: (state: "connected" | "disconnected") => void): DeregisterFn;
get isConnected(): boolean;
/**
* Wait for the state to be connected.
*
* If a disconnect (e.g. due to unmount) is requested before being
* connected, the promise will be rejected to ensure the promise
* is fulfilled.
*/
connectedPromise(): Promise<void>;
sendRequest<R>(action: string): Promise<R>;
sendRequest<T, R>(action: string, payload: T, transfer?: Transferable[]): Promise<R>;
sendEvent(action: string): Promise<void>;
sendEvent<T>(action: string, payload: T, transfer?: Transferable[]): Promise<void>;
createSubscription<T, O extends Record<string, unknown> = Record<string, unknown>>(name: string, handler: (event: T) => void, options?: O): Promise<CreateSubscriptionResult>;
}
export {};