UNPKG

@amadeus-it-group/microfrontends

Version:
462 lines (455 loc) 14.6 kB
/** * A message that is sent between peers */ interface Message { /** * Message type */ type: string; /** * Message version */ version?: string; } /** * A versioned message */ interface VersionedMessage extends Message { /** * @inheritDoc */ version: string; } /** * A functional message wrapper that contains the message payload and the sender and receiver ids. * It is used to route messages between peers. */ interface RoutedMessage<M extends Message> { /** * Id of the sender peer */ from: string; /** * Id of the receiver peer(s). If it is an empty array, the message is broadcasted to all peers. */ to: string[]; /** * Message payload - an actual {@link Message} subtype that is sent between peers */ payload: M; } /** * A service message that is sent when an error occurs during the message processing. * It will be routed back to the sender of the message when parsing/validation exception occurs * on the receiver side. */ interface ErrorMessage extends Message { /** * Message type */ type: 'error'; /** * Message version */ version: '1.0'; /** * Error message */ error: string; /** * The original message that caused the error */ message: RoutedMessage<Message>; } /** * A service message that is sent when a new {@link MessagePeerType} connects to the network. * It contains the list of new peers and messages they can receive. */ interface ConnectMessage extends Message { /** * Message type */ type: 'connect'; /** * Message version */ version: '1.0'; /** * List of new peers and messages they receive */ knownPeers: Map<string, Message[]>; /** * List of peers ids that have just connected to the network */ connected: string[]; } /** * A service message that is sent when a {@link MessagePeerType} disconnects from the network. * It contains the list of peers that are unreachable from the disconnected peer. */ interface DisconnectMessage extends Message { /** * Message type */ type: 'disconnect'; /** * Message version */ version: '1.0'; /** * Id of the disconnected peer */ disconnected: string; /** * List of peers that are not reachable anymore from the disconnected peer */ unreachable: string[]; } /** * A service message that is sent when an {@link Endpoint} connects to another `Endpoint. * This message stays internal and not propagated to the end user. */ interface HandshakeMessage extends Message { /** * Message type */ type: 'handshake'; /** * Message version */ version: '1.0'; /** * Id of the endpoint that receives the message */ endpointId: string; /** * Id of the endpoint that has sent the message */ remoteId: string; /** * List of known peers and messages that remote endpoint knows about. */ knownPeers: Map<string, Message[]>; } /** * A service message that is sent by a {@link MessagePeerType} that starts accepting new message types. */ interface DeclareMessages extends Message { /** * Message type */ type: 'declare_messages'; /** * Message version */ version: '1.0'; /** * List of message types (type, version) that the sender of the messages accepts */ messages: Message[]; } /** * A type that represents a service message that is used by the library to communicate between peers, * maintain the network and handle errors. */ type ServiceMessage = HandshakeMessage | DeclareMessages | ErrorMessage | DisconnectMessage | ConnectMessage; /** * Checks if a particular message is a {@link ServiceMessage}, like `connect`, `disconnect`, `handshake`, etc. * * ```ts * // Example of usage * if (isServiceMessage(message)) { * switch (message.type) { * case 'connect': * // handle connect message with narrowed type * break; * } * } * ``` * @param message - Message to check */ declare function isServiceMessage(message: Message): message is ServiceMessage; /** * Error class for errors related to message processing * @param message - The error message * @param messageObject - The message that caused the error */ declare class MessageError extends Error { messageObject: RoutedMessage<Message>; constructor(messageObject: RoutedMessage<Message>, message: string); } /** * A strategy that a message peer uses to check messages upon reception. * - `default` - checks that the message structure is correct (from, to, type, version and payload are present) * - `type` - checks that the message type is known for the peer * - `version` - checks that the message version is known for the peer */ type MessageCheckStrategy = 'default' | 'type' | 'version'; declare global { interface SymbolConstructor { readonly observable: symbol; } } type SubscriberFunction<T> = (value: T) => void; interface SubscriberObject<T> { next?: SubscriberFunction<T>; } type Subscriber<T> = SubscriberObject<T> | SubscriberFunction<T> | null | undefined; interface Subscription { unsubscribe(): void; } /** * An Observable-compatible interface for consuming messages. * * It can also be used with rxjs, for example: * * ```ts * import { from } from 'rxjs'; * * const peer = new MessagePeer({...}); * const observable = from(peer.messages); * ``` */ interface Subscribable<T> { [Symbol.observable](): Subscribable<T>; subscribe(subscriber: Subscriber<T>): Subscription; } /** * Options to establish peer connection. * Useful to connect to a different window or an iframe. */ interface PeerConnectionOptions { /** * Window object peer should connect to. * Default is `window` object of the current environment. * It can be used to connect to a different window or an iframe. */ window?: Window; /** * Origin of the window object peer should connect to. * Default is `window.origin` of the current environment. * Used to verify that the connection is established with the correct window from different origin. */ origin?: string; } /** * Function that filters incoming connections based on the message and its source. * @param message - the message received from the peer * @param source - the source of the message * @param origin - the origin of the message */ type PeerConnectionFilterFn = (message: RoutedMessage<HandshakeMessage>, source: MessageEventSource | null, origin: string) => boolean; /** * Filter for incoming connections. */ interface PeerConnectionFilter { /** * Id of a peer allowed to connect. */ id?: string; /** * Window object for allowed incoming connections. * Default is `window` object of the current environment. * It can be used to connect to a different window or an iframe. */ source?: MessageEventSource; /** * Origin of allowed incoming connections. * Default is `window.origin` of the current environment. * Used to verify that the connection is established with the correct window from different origin. */ origin?: string; } /** * Options to pass when sending a message to the network. */ interface PeerSendOptions { /** * List of peer ids that should receive the message. * If not provided or an empty array, the message will be received by all connected peers. */ to?: string | string[]; } /** * Options to pass when creating a new peer. * The only required option is the unique `id` of the peer. */ interface PeerOptions { /** * Unique identifier of the peer on the network it will be connected to */ id: string; /** * List of known messages that the peer can receive, it can be amended later with {@link MessagePeerType#registerMessage()} method */ knownMessages?: Message[]; /** * Defines how peer will validate messages upon reception. * By 'default' it will check only that the message structure is correct. */ messageCheckStrategy?: MessageCheckStrategy; } /** * A type that represents a peer in the network that can send and receive messages. */ interface MessagePeerType<M extends Message> { /** * Unique identifier of the peer on the network */ get id(): string; /** * List of other known peers on the network and types of messages they can receive */ get knownPeers(): Map<string, Message[]>; /** * List of peers reachable from connected peers. */ get peerConnections(): Map<string, Set<string>>; /** * A {@link Subscribable} that emits a message received by the peer * To handle {@link ServiceMessage} like `connect` or `disconnect`, use the {@link MessagePeer#serviceMessages} stream. */ get messages(): Subscribable<RoutedMessage<M>>; /** * A {@link Subscribable} that emits a {@link ServiceMessage} is received by the peer. */ get serviceMessages(): Subscribable<RoutedMessage<ServiceMessage>>; /** * A {@link Subscribable} that emits an error occurs during received message processing locally. * The {@link ErrorMessage} will be sent back to the sender of the message automatically */ get errors(): Subscribable<MessageError>; /** * Connects to the peer with the given id * @param remoteId - a remote peer id to connect to * @param options - additional {@link PeerConnectionOptions} options for the connection * @returns a function that can be called to disconnect this peer from the network */ connect(remoteId: string, options?: PeerConnectionOptions): Promise<() => void>; /** * Listens for incoming connections from any peers that match the provided filters. * @param filters - optional filters to use to accept incoming connections. If not provided, * accepts all incoming connections, otherwise tries to match at least one of the filters. Can be * a string with peer id, a {@link PeerConnectionFilter} object or an array of such objects. * @returns a function that can be called to disconnect this peer from the network */ listen(filters?: string | PeerConnectionFilter | PeerConnectionFilterFn | readonly (string | PeerConnectionFilter)[]): () => void; /** * Sends a message to the network. * * Message must be a serializable object supported by `structuredClone()` algorithm. * Message send can happen synchronously or asynchronously depending on how the peer is connected. * By default, the message is broadcast to all connected peers. * * If you need to send a message to a specific peer only, use {@link PeerSendOptions#to} option. * * If there are no connected peers, the message will be queued until * the first connection is established. * * @param message - message to send * @param options - additional {@link PeerSendOptions} for the message delivery */ send(message: M, options?: PeerSendOptions): void; /** * Registers a new message that this peer can receive. * @param message - message type and version to register */ registerMessage(message: Message): void; /** * Disconnects this peer from the network completely or from a particular peer. * If no `peerId` is provided, disconnects completely from the network. * @param peerId - a specific peer id to disconnect from */ disconnect(peerId?: string): void; } /** * Default message peer that can send and receive messages to/from other peers in the same document * or across different windows or iframes. * * Messages will be sent in a synchronous way if both peers are in the same window. * Otherwise, a `MessageChannel` will be established to send messages between different windows. * * ```ts * // Simple example of creating two peers and sending messages between them * const one = new MessagePeer({ id: 'one' }); * const two = new MessagePeer({ id: 'two' }); * * // connecting two peers * one.listen(); * two.connect('one'); * * // sending messages * one.send({ type: 'ping', version: '1.0' }); // broadcast * two.send({ type: 'pong', version: '1.0' }, { to: 'one' }); // send to a specific peer * * // receiving messages * one.messages.subscribe((message) => {}); // receives all messages sent to 'one' * one.serviceMessages.subscribe((message) => {}); // receives service messages like 'connect', 'disconnect', etc. * * // learning about the network * one.knownPeers; // lists all known peers and messages they can receive * * // disconnecting * one.disconnect(); // disconnects from all peers * one.disconnect('two'); // disconnects from a specific peer * ``` */ declare class MessagePeer<M extends Message> implements MessagePeerType<M> { #private; constructor(options: PeerOptions); /** * @inheritDoc */ get id(): string; /** * @inheritDoc */ get knownPeers(): Map<string, Message[]>; /** * @inheritDoc */ get peerConnections(): Map<string, Set<string>>; /** * @inheritDoc */ get messages(): Subscribable<RoutedMessage<M>>; /** * @inheritDoc */ get serviceMessages(): Subscribable<RoutedMessage<ServiceMessage>>; /** * @inheritDoc */ get errors(): Subscribable<MessageError>; /** * @inheritDoc */ connect(remoteId: string, options?: PeerConnectionOptions): Promise<() => void>; /** * @inheritDoc */ send(message: M, options?: PeerSendOptions): void; /** * @inheritDoc */ listen(filters?: string | PeerConnectionFilter | PeerConnectionFilterFn | readonly (string | PeerConnectionFilter)[]): () => void; /** * @inheritDoc */ registerMessage(message: Message): void; /** * Logs the current state of the peer to the console */ log(): void; /** * @inheritDoc */ disconnect(peerId?: string): void; } /** * If true, tracing information to help debugging will be logged in the console * @param enabled */ declare function enableLogging(enabled?: boolean): void; export { MessageError, MessagePeer, enableLogging, isServiceMessage }; export type { ConnectMessage, DeclareMessages, DisconnectMessage, Message, MessageCheckStrategy, MessagePeerType, PeerConnectionFilter, PeerConnectionFilterFn, PeerConnectionOptions, PeerOptions, PeerSendOptions, RoutedMessage, ServiceMessage, Subscribable, VersionedMessage };