Typesafe distributed computing in the browser.
npm install @daniel-nagy/transporter-browserThe browser package contains APIs designed to work in the browser.
```
npm add @daniel-nagy/transporter @daniel-nagy/transporter-browser
Transporter is distributed as ES modules.
Transporter may also be imported directly in the browser from a URL. For example,
`html`
The browser package contains the following modules.
- BroadcastSubject
- BrowserClient
- BrowserRequest
- BrowserResponse
- BrowserServer
- BrowserSocket
- BrowserSocket.Message
- BrowserSocket.State
- BrowserSocketServer
- StructuredCloneable
_Module_
A BroadcastSubject can be used to synchronize state between same-origin browsing contexts or workers.
###### Types
###### Constructors
_Type_
`ts`
class BroadcastSubject
A BroadcastSubject is a Subject that broadcasts emitted values over a BroadcastChannel.
#### FromChannel
_Constructor_
`ts`
function fromChannel
name: string
): BroadcastSubject
Creates a BroadcastSubject from a broadcast channel name.
##### Example
`ts`
import * as BroadcastSubject from "@daniel-nagy/transporter-browser/BroadcastSubject";
const darkMode = BroadcastSubject.fromChannel("darkMode");
darkMode.subscribe(console.log);
_Module_
An interface for making requests to a browsing context or worker.
###### Types
###### Constants
- SW
###### Constructors
- from
###### Methods
- fetch
_Type_
`ts`
class BrowserClient {
/**
* The address of the server. An address is like a port number, except an
* address can be any string instead of a meaningless number.
*/
public readonly serverAddress: string;
/**
* If the window and the origin do not match the connection will fail. The
* origin is only relevant when connecting to a window since the browser
* will require worker URLs to be same-origin.
*/
public readonly origin: string;
/**
* The message target. A message target is like a server host.
*/
public readonly target: Window | Worker | SharedWorker | SW;
}
An object that may be used to make fetch requests to a browsing context or worker.
#### Options
_Type_
`tsWindow
type Options = {
/**
* The address of the server. The default is the empty string.
*/
address?: string;
/**
* When connecting to a you may specify the allowed origin. If thetargetOrigin
* window and the origin do not match the connection will fail. The origin is
* passed directly to the parameter of postMessage when""
connecting to the window. The default is , which allows any origin.`
*/
origin?: string;
};
Options when creating a BrowserClient.
#### SW
_Constant_
`ts`
const SW = Symbol.for("ServiceWorker");
An atom that symbolizes a ServiceWorker. When used as a target the client will make requests to the currently active ServiceWorker.
##### Example
`ts
import * as BrowserClient from "@daniel-nagy/transporter-browser/BrowserClient";
await navigator.serviceWorker.register("./sw.js", {
type: "module"
});
const client = BrowserClient.from(BrowserClient.SW);
`
#### From
_Constructor_
`ts`
function from(
target: Window | Worker | SharedWorker | SW,
options?: Options
): BrowserClient;
Creates a new BrowserClient.
##### Example
`ts
import * as BrowserClient from "@daniel-nagy/transporter-browser/BrowserClient";
const worker = new Worker("/worker.js", { type: "module" });
const client = BrowserClient.from(worker);
`
#### Fetch
_Method_
`ts`
fetch(body: StructuredCloneable.t): Promise
Makes a request to a BrowserServer.
##### Example
`ts
import * as BrowserClient from "@daniel-nagy/transporter-browser/BrowserClient";
const worker = new Worker("/worker.js", { type: "module" });
const client = BrowserClient.from(worker);
const response = await client.fetch("👋");
`
_Module_
A server receives a Request object when a client makes a request.
###### Types
- Request
###### Functions
#### Request
_Type_
`tsMessageEvent.origin
type Request = {
address: string;
/**
* Contains the value sent by the client.
*/
body: StructuredCloneable.t;
id: string;
/**
* The origin of the client making the request. The origin will be set
* securely on the server using .`
*/
origin: string;
type: "Request";
};
A Request is created when a client makes a fetch request.
#### IsRequest
_Function_
`ts`
function isRequest(event: MessageEvent): event is MessageEvent
Returns true if the message event contains a Request object.
_Module_
A server sends a Response to a client in response to a request.
###### Types
- Response
###### Functions
#### Response
_Type_
`ts`
type Response = {
/**
* The payload of the response. This is the value the client will receive.
*/
body: StructuredCloneable.t;
id: string;
type: "Response;
};
A Response is created from the value returned by the server's request handler.
#### IsResponse
_Function_
`ts`
function isResponse(event: MessageEvent): event is MessageEvent
Returns true if the message event contains a Response object.
_Module_
A BrowserServer provides request/response semantics on top of postMessage. It also normalizes the interface for connecting to different types of processes in the browser.
###### Types
- BrowserServer
- Options
- RequestHandler
- State
###### Constructors
- listen
###### Methods
- stop
_Type_
`ts`
class BrowserServer {
public readonly address: string;
public readonly handle: RequestHandler;
public readonly state: State;
public readonly stateChange: Observable.t
public readonly stopped: Observable.t
}
A BrowserServer listens for incoming requests from clients.
_Type_
`ts`
type Options = {
/**
* The address of the server. The default is the empty string. All servers
* must have a globally unique address.
*/
address?: string;
/**
* Called whenever a request is received from a client. The request handler
* may return anything that is structured cloneable.
*
* The request object will contain the origin of the client. The origin can be
* used to validate the client before fulfilling the request.
*/
handle: RequestHandler;
};
Options when creating a BrowserServer.
#### RequestHandler
_Type_
`ts`
type RequestHandler = (
request: Readonly
) => StructuredCloneable.t | Promise
A RequestHandler receives a Request from a client and returns the body of the Response that will be sent back to the client.
#### State
_Type_
`ts`
enum State {
Listening = "Listening",
Stopped = "Stopped"
}
An enumerable of the different server states.
#### Listen
_Constructor_
`ts`
function listen(options: Options): BrowserServer;
Creates a new BrowserServer in the global scope. A UniqueAddressError will
be thrown if the address is already taken.
#### Example
`ts
import * as BrowserServer from "@daniel-nagy/transporter/BrowserServer";
const server = BrowserServer.listen({
handle(request) {
// Message received from client. Return any response.
return "👋";
}
});
`
#### Stop
_Method_
`ts`
stop(): void;
Stops the server. Once stopped the server will no longer receive requests.
#### Example
`ts
import * as BrowserServer from "@daniel-nagy/transporter/BrowserServer";
const server = BrowserServer.listen({
handle(request) {}
});
server.stop();
`
_Module_
Provides a socket API on top of postMessage that is similar to the WebSocket API. A BrowserSocket is connection-oriented, duplex, and unicast. Any data that is structured cloneable can be passed through a browser socket.
###### Types
- BrowserSocket
- ConnectionError
- ConnectTimeoutError
- DisconnectTimeoutError
- HeartbeatTimeoutError
- Options
- WindowOptions
###### Constructors
- connect
###### Methods
_Type_
`tsClosed
class BrowserSocket {
/**
* Emits when the socket's state changes to and then completes.Closing
*/
public readonly closed: Observable.t
/**
* Emits when the socket's state changes to and then completes.Connected
*/
public readonly closing: Observable.t
/**
* Emits if the socket's state changes to and then completes. IfClosed
* the socket errors during connection it will complete without emitting.
*/
public readonly connected: Observable.t
/**
* Emits when the socket receives data.
*/
public readonly receive: Observable.t
/**
* The current state of the socket.
*/
public readonly state: State;
/**
* Emits when the socket's state changes. Completes when the socket state
* becomes .`
*/
public readonly stateChange: Observable.t
}
A BrowserSocket is used to create a connection between browsing contexts or a browsing context and a worker context.
#### ConnectionError
_Type_
`ts`
type ConnectionError =
| Observable.BufferOverflowError
| ConnectTimeoutError
| HeartbeatTimeoutError;
A variant type for the different reasons a socket may transition to a closing state with an error.
#### ConnectTimeoutError
_Type_
`ts`
class ConnectTimeoutError extends Error {}
Used to indicate that the connection failed because the server did not complete the connection in the allotted time.
#### DisconnectTimeoutError
_Type_
`ts`
class DisconnectTimeoutError extends Error {}
Used to indicate that an acknowledgement was not received when closing the connection in the allotted time.
#### HeartbeatTimeoutError
_Type_
`ts`
class HeartbeatTimeoutError extends Error {}
Used to indicate that a response to a health-check was not received in the allotted time.
_Type_
`tsInfinity
interface Options {
/**
* The maximum number of messages to buffer before the socket is connected.
* The default is .2000
*/
bufferLimit?: number;
/**
* What to do incase there is a buffer overflow. The default is to error.
*/
bufferOverflowStrategy?: Observable.BufferOverflowStrategy;
/**
* The maximum amount of time to wait for a connection in milliseconds. The
* default is or 2 seconds.2000
*/
connectTimeout?: number;
/**
* The maximum amount of time to wait for a disconnection in milliseconds. The
* default is or 2 seconds.1000
*/
disconnectTimeout?: number;
/**
* The frequency at which to request heartbeats in milliseconds. The default
* is or 1 second.2000
*/
heartbeatInterval?: number;
/**
* The maximum amount of time to wait for a heartbeat in milliseconds. The
* default is or 2 seconds.`
*/
heartbeatTimeout?: number;
/**
* The address of the socket server.
*/
serverAddress?: string;
}
Options when creating a BrowserSocket.
#### WindowOptions
_Type_
`tsWindow
interface WindowOptions extends Options {
/**
* When connecting to a you may specify the allowed origin. If thetargetOrigin
* window and the origin do not match the connection will fail. The origin is
* passed directly to the parameter of postMessage when""
connecting to the window. The default is , which allows any origin.`
*/
origin?: string;
}
Additional options when connecting to a browsing context.
#### Connect
_Constructor_
`ts`
function connect(
target: SharedWorker | Window | Worker,
options?: Options | WindowOptions
): BrowserSocket;
Creates a new BrowserSocket. The socket will start in a Connecting state.
##### Example
`ts`
import * as BrowserSocket from "@daniel-nagy/transporter/BrowserSocket";
using socket = BrowserSocket.connect(self.parent);
#### Close
_Method_
`ts`
close(): void;
Closes the socket causing its state to transition to Closing.
##### Example
`ts`
import * as BrowserSocket from "@daniel-nagy/transporter/BrowserSocket";
const socket = BrowserSocket.connect(self.parent);
socket.close();
#### Ping
_Method_
`ts`
ping(timeout: number = 2000): Promise
Sends a ping to a connected socket and waits for a pong to be sent back. Returns a promise that resolves when a pong is received or rejects if a pong is not received in the allotted time.
##### Example
`ts`
import * as BrowserSocket from "@daniel-nagy/transporter/BrowserSocket";
using socket = BrowserSocket.connect(self.parent);
await socket.ping();
#### Send
_Method_
`ts`
send(message: StructuredCloneable.t): void;
Sends data through the socket. Data will automatically be buffered until the socket connects.
##### Example
`ts`
import * as BrowserSocket from "@daniel-nagy/transporter/BrowserSocket";
const socket = BrowserSocket.connect(self.parent);
socket.send("👋");
_Module_
Internal messages to facilitate the socket API. These messages are filtered from the data received from the socket.
###### Types
- Connect
- Connected
- Disconnect
- Disconnected
- Message
- Ping
- Pong
- Type
###### Functions
_Type_
`ts`
type Connect = {
address: string;
type: Type.Connect;
};
Sent when a connection is initiated. This starts the "handshake".
#### Connect
_Type_
`ts`
type Connected = {
type: Type.Connected;
};
A message indicating the connection is complete and was successful. This concludes the "handshake".
#### Disconnect
_Type_
`ts`
type Disconnect = {
type: Type.Disconnect;
};
Sent when a socket is closing so that the other endpoint may preform some cleanup logic or otherwise close the connection gracefully. This starts the "closing handshake".
#### Disconnected
_Type_
`ts`
type Disconnected = {
type: Type.Disconnected;
};
A message that acknowledges the disconnection. If this message is received then the disconnect was graceful. This concludes the "closing handshake".
#### Message
_Type_
`ts`
export type Message =
| Connect
| Connected
| Disconnect
| Disconnected
| Ping
| Pong;
A variant type for the different types of messages.
_Type_
`ts`
type Ping = {
id: string;
type: Type.Ping;
};
A ping message may be sent to solicit a response from the other endpoint.
#### Pong
_Type_
`ts`
type Pong = {
id: string;
type: Type.Pong;
};
A pong message must always be sent in response to a ping message.
#### Type
_Type_
`ts`
enum Type {
Connect = "Connect",
Connected = "Connected",
Disconnect = "Disconnect",
Disconnected = "Disconnected",
Ping = "Ping",
Pong = "Pong"
}
An enumerable of the different types of socket messages.
#### IsMessage
_Function_
`ts`
function isMessage(message: StructuredCloneable.t): message is Message;
Returns true if the message is a socket message.
#### IsType
_Function_
`ts`
function isType
message: StructuredCloneable.t,
type: T
): message is {
[Type.Connect]: Connect;
[Type.Connected]: Connected;
[Type.Disconnect]: Disconnect;
[Type.Disconnected]: Disconnected;
[Type.Ping]: Ping;
[Type.Pong]: Pong;
}[T];
Returns true if the message is of the specified type.
#### TypeOf
_Function_
`ts`
function typeOf(message: StructuredCloneable.t): Type | null;
Returns the message Type if the message is a socket message. Returns null otherwise.
_Module_
A socket's state.
###### Types
- Closed
- Closing
- Connected
- Connecting
- State
- Type
#### Closed
_Type_
`ts`
type Closed
error?: E;
type: Type.Closed;
};
The socket is closed, possibly with an error.
#### Closing
_Type_
`ts`
type Closing
error?: E;
type: Type.Closing;
};
The socket is closing, possibly with an error.
_Type_
`ts`
type Connected = {
type: Type.Connected;
};
The socket is connected.
#### Connecting
_Type_
`ts`
type Connecting = {
type: Type.Connecting;
};
The socket is connecting.
_Type_
`ts`
type State =
| Connecting
| Connected
| Closing
| Closed
A variant type for the different socket states.
_Type_
`ts`
enum Type {
Connecting = "Connecting",
Connected = "Connected",
Closing = "Closing",
Closed = "Closed"
}
An enumerable of the different socket states.
_Module_
A BrowserSocketServer listens for socket connect requests. When a request is received it will create a corresponding socket server side and complete the handshake.
###### Types
- BrowserSocketServer
- Options
- SocketOptions
- State
###### Constructors
- listen
###### Methods
- stop
_Type_
`ts`
class BrowserSocketServer {
public readonly address: string;
public readonly connect: Observable.t
public readonly state: State;
public readonly stateChange: Observable.t
public readonly stopped: Observable.t
}
Creates socket connections as requests come in.
_Type_
`ts`
type Options = {
/**
* The address of the server. The default is an empty string.
*/
address?: string;
/**
* Allows intercepting connection requests and denying the request if
* necessary.
*/
connectFilter?(message: MessageEvent
/**
* Forwarded to the socket that is created on connection.
*/
socketOptions?: SocketOptions;
};
Options when creating a BrowserSocketServer.
#### SocketOptions
_Type_
`ts`
type SocketOptions = {
disconnectTimeout?: number;
heartbeatInterval?: number;
heartbeatTimeout?: number;
};
Options forwarded to the BrowserSocket when it is created.
_Type_
`ts`
enum State {
Listening = "Listening",
Stopped = "Stopped"
}
An enumerable of the different server states.
_Constructor_
`ts`
function listen(options?: Options): BrowserSocketServer;
Creates a new BrowserSocketServer. Throws a UniqueAddressError if the address is already taken.
#### Example
`ts
import * as BrowserSocketServer from "@daniel-nagy/transporter/BrowserSocketServer";
const server = BrowserSocketServer.listen();
server.connect.subscribe((socket) => socket.send("👋"));
`
_Method_
`ts`
function stop(): void;
Stops the server. A disconnect message will be sent to all connected clients.
#### Example
`ts
import * as BrowserSocketServer from "@daniel-nagy/transporter/BrowserSocketServer";
const server = BrowserSocketServer.listen();
server.stop();
`
_Module_
A StructuredCloneable type can be passed between processes in the browser.
###### Types
- StructuredCloneable
- TypedArray
_Type_
`ts`
type StructuredCloneable =
| void
| null
| undefined
| boolean
| number
| bigint
| string
| Date
| ArrayBuffer
| RegExp
| TypedArray
| Array
| Map
| Set
| { [key: string]: StructuredCloneable };
A value that can be cloned using the structured clone algorithm.
#### TypedArray
_Type_
`ts`
type TypedArray =
| BigInt64Array
| BigUint64Array
| Float32Array
| Float64Array
| Int8Array
| Int16Array
| Int32Array
| Uint8Array
| Uint8ClampedArray
| Uint16Array
| Uint32Array;
A TypedArray` object describes an array-like view of an underlying binary data buffer.