Typesafe distributed computing in TypeScript.
npm install @daniel-nagy/transporterThe core package contains APIs designed to work in any JavaScript runtime.
```
npm add @daniel-nagy/transporter
Transporter is distributed as ES modules. Generally speaking, modules encapsulate a type and export functions that act as either a constructor or operator on that type. The module has the same name as the type it encapsulates. You will often see this type reexported with the alias t. This is a common convention found in functional programming languages that allows dereferencing the type from the module without typing out the name twice, which feels icky. This makes using namespace imports with Transporter modules a bit nicer. For example,
`typescript
import * as Observable from "@daniel-nagy/transporter/Observable";
// To access the type you need to type Observable twice 🤮.
const observable: Observable.Observable = Observable.of(1, 2, 3);
// Equivalent to the above. Not perfect but better.
const observable: Observable.t = Observable.of(1, 2, 3);
`
Transporter makes heavy use of namespace imports internally. If that makes you concerned about tree-shaking then don't be. Webpack, Rollup, and esbuild all handle namespace imports fine. It is namespace exports that may be problematic when it comes to tree-shaking. Though both webpack and Rollup seem to handle those as well, making esbuild the standout.
Transporter contains the following modules.
- BehaviorSubject
- Cache
- Injector
- Json
- Message
- Metadata
- Observable
- Proxy
- PubSub
- Session
- Subject
- Subprotocol
- SuperJson
_Module_
A BehaviorSubject is a Subject that replays the most recent value when subscribed to.
###### Types
###### Constructors
- of
###### Methods
- getValue
_Type_
`ts`
class BehaviorSubject
A Subject that replays the last emitted value.
#### Of
_Constructor_
`ts`
function of
Creates a new BehaviorSubject with an initial value of type T.
##### Example
`ts
import * as BehaviorSubject from "@daniel-nagy/transporter/BehaviorSubject";
BehaviorSubject.of("👍").subscribe(console.log);
`
#### GetValue
_Method_
`ts`
getValue(): T;
The getValue method can be used to synchronously retrieve the value held by the BehaviorSubject. If the BehaviorSubject is in an error state then getValue will throw the error.
##### Example
`ts
import * as BehaviorSubject from "@daniel-nagy/transporter/BehaviorSubject";
BehaviorSubject.of("👍").getValue();
`
_Module_
A Cache may be used to memoize remote function calls. Transporter guarantees that proxies are referentially stable so other memoization APIs are likely compatible with Transporter as well.
In order to memoize a function its arguments must be serializable. A stable algorithm is used to serialize a function's arguments and index the cache. The cache supports any arguments of type SuperJson.
###### Types
- Cache
###### Constructors
- init
###### Methods
- add
- get
- has
- memo
- remove
- update
_Type_
`ts`
class Cache {}
A Cache is used to memoize remote function calls. A Cache is double-keyed by a function and its arguments.
#### Init
_Constructor_
`ts`
function init(): Cache;
Creates a new Cache.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const cache = Cache.init();
`
#### Add
_Method_
`ts`
add(func: JsFunction.t, args: SuperJson.t[], value: unknown): void;
Adds the value to the cache for the specified function and arguments. Used internally by the memo method, which is the preferred way to add a value to the cache.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
Cache.init().add(identity, "🥸", "🥸");
`
#### Get
_Method_
`ts`
get
func: (...args: Args) => Return,
args: Args
): Return | NotFound;
Get a value from the cache. Returns NotFound if the value does not exist.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
Cache.init().get(identity, "🥸"); // NotFound
`
#### Has
_Method_
`ts`
has(func: JsFunction.t, args?: SuperJson.t[]): boolean
Checks if the value is in the cache. If no arguments are provided then it will return true if any value is cached for the function.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
Cache.init().has(identity, "🥸"); // false
`
#### Memo
_Method_
`ts`
memo
func: (...args: Args) => Return
): (...args: Args) => Return
Takes a function as input and returns a memoized version of the same function as output. Using a memoized function is the preferred way of adding values to the cache.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
const cache = Cache.init();
const memo = Cache.memo(identity);
memo("🥸");
cache.has(identity, "🥸"); // true
`
#### Remove
_Method_
`ts`
remove(func: JsFunction.t, args?: SuperJson.t[]): boolean
Removes a value from the cache. Returns true if the value was found and removed. If no arguments are provided then all values for that function will be removed.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
const cache = Cache.init();
const memo = Cache.memo(identity);
memo("🥸");
cache.remove(identity, "🥸"); // true
`
#### Update
_Method_
`ts`
update
func: (...args: Args) => Return,
args: Args,
callback: (value: Return) => Return
): void
Updates a value in the cache. The callback function will receive the current value in the cache. Does nothing if there is a cache miss on the value.
##### Example
`ts
import * as Cache from "@daniel-nagy/transporter/Cache";
const identity = (value) => value;
const cache = Cache.init();
const memo = Cache.memo(identity);
memo("🥸");
cache.update(identity, "🥸", () => "🤓");
`
_Module_
An Injector is IoC container and can be used to inject dependencies into functions invoked by Transporter.
###### Types
###### Constructors
###### Methods
###### Functions
_Type_
`ts`
class Injector {}
An Injector is a dependency container. Values may be added or read from the container using tags.
#### Tag
_Type_
`ts`
type Tag
A Tag is a value that is bound to a single dependency type and is used to index the container.
#### Empty
_Constructor_
`ts`
function empty(): Injector;
Creates a new empty Injector.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
const injector = Injector.empty();
`
_Constructor_
`ts`
function Tag
Creates a new Tag.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
type Session = {
userId?: string;
};
const SessionTag = Injector.Tag
`
_Method_
`ts`
function add
Adds a value to the container.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
type Session = {
userId?: string;
};
const SessionTag = Injector.Tag
const Session: Session = { userId: "User_123" };
Injector.empty().add(SessionTag, Session);
`
_Method_
`ts`
function get(tag: Tag
Gets a value from the container using a Tag.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
const tag = Injector.Tag
Injector.empty().get(tag);
`
#### GetTags
_Function_
`ts`
function getTags(func: JsFunction.t): : Tag
Returns a list of tags from a function returned by provide. If the function does not have DI metadata an empty list is returned.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
const getUser = Injector.provide([Prisma, Session], (prisma, session) =>
prisma.user.findUnique({ where: { id: session.userId } })
);
Injector.getTags(getUser);
`
#### Provide
_Function_
`ts`
function provide<
const Tags extends readonly Tag
const Args extends [...Values
const Return
>(
tags: Tags,
func: (...args: Args) => Return
): (...args: JsArray.DropFirst
Returns a new function that has a list of tags stored as metadata. The call signature of the new function will omit any injected dependencies. Type parameters of generic functions will be propagated to the new function.
##### Example
`ts
import * as Injector from "@daniel-nagy/transporter/Injector";
const getUser = Injector.provide(
[Prisma, Session],
(prisma, session, select: S) =>
prisma.user.findUnique({ where: { id: session.userId }, select })
);
// $ExpectType
// const getUser = (
// select: S
// ) => Prisma.Prisma__User | null;
`
_Module_
A Json type may be used as a data type for a subprotocol. If both ends of your communication channel are JavaScript runtimes then you may use the SuperJson module instead for a much larger set of types.
###### Types
- Json
###### Functions
_type_
`ts`
export type Json =
| null
| number
| string
| boolean
| { [key: string]: Json }
| Json[];
Represents a JSON value.
#### Serialize
`ts`
function serialize(value: Json): string;
Serializes a JSON value in a way that is deterministic, such that 2 strings are equal if they encode the same value.
##### Example
`ts
import * as Json from "@daniel-nagy/transporter/Json";
Json.serialize({ name: "Jane Doe" });
`
#### sortDeep
`ts`
function sortDeep(value: Json): Json;
Recursively sorts the properties of an object. Array values retain their sort order.
##### Example
`ts
import * as Json from "@daniel-nagy/transporter/Json";
Json.sortDeep({
c: "c",
b: [{ f: "f", e: "e" }, 12],
a: "a"
});
// $ExpectType
// {
// a: "a",
// b: [{ e: "e", f: "f" }, 12],
// c: "c"
// }
`
_Module_
Defines the Transporter message protocol. The creation and interpretation of messages should be considered internal. However, it is ok to intercept message and perform your own logic or encoding.
###### Types
- CallFunction
- Error
- GarbageCollect
- Message
- SetValue
- Type
- Version
###### Constants
###### Functions
- isCompatible
- isMessage
- parseVersion
#### CallFunction
_Type_
`ts`
type CallFunction
readonly address: string;
readonly args: Args;
readonly id: string;
readonly noReply: boolean;
readonly path: string[];
readonly protocol: "transporter";
readonly type: Type.Call;
readonly version: Version;
};
A Call message is sent to the server to call a remote function.
#### Error
_Type_
`ts`
type Error
readonly address: string;
readonly error: Error;
readonly id: string;
readonly protocol: "transporter";
readonly type: Type.Error;
readonly version: Version;
};
An Error message is sent to the client when calling a remote function throws or rejects.
#### GarbageCollect
_Type_
`ts`
type GarbageCollect = {
readonly address: string;
readonly id: string;
readonly protocol: "transporter";
readonly type: Type.GarbageCollect;
readonly version: Version;
};
A GarbageCollect message is sent to the server when a proxy is disposed on the client.
_Type_
`ts`
type Message
| CallFunction
| Error
| GarbageCollect
| SetValue
A discriminated union of the different message types.
#### SetValue
_Type_
`ts`
type SetValue
readonly address: string;
readonly id: string;
readonly protocol: "transporter";
readonly type: Type.Set;
readonly value: Value;
readonly version: Version;
};
A Set message is sent to the client after calling a remote function.
#### Type
_Type_
`ts`
enum Type {
Call = "Call",
Error = "Error",
GarbageCollect = "GarbageCollect",
Set = "Set"
}
An enumerable of the different message types.
#### Version
_Type_
`ts${number}.${number}.${number}
type Version = ;`
A semantic version string.
#### Protocol
_Constant_
`ts`
const protocol = "transporter";
The name of the protocol.
#### Version
_Constant_
`ts`
const version: Version;
The version of the protocol.
#### IsCompatible
_Function_
`ts`
function isCompatible(messageVersion: Version): boolean;
Returns true if a message is compatible with the current protocol version. A
message is considered compatible if its major and minor versions are the same.
##### Example
`ts
import * as Message from "@daniel-nagy/transporter/Message";
Message.isCompatible(message);
`
#### IsMessage
_Function_
`ts`
function isMessage
message: T | Message
): message is Message
Returns true if the value is a Transporter message.
##### Example
`ts
import * as Message from "@daniel-nagy/transporter/Message";
Message.isMessage(value);
`
#### ParseVersion
_Function_
`ts`
function parseVersion(
version: Version
): [major: string, minor: string, patch: string];
Parses a semantic version string and returns a tuple of the version segments.
##### Example
`ts
import * as Message from "@daniel-nagy/transporter/Message";
Message.parseVersion(message.version);
`
_Module_
The Metadata module allows information to be extracted from a proxy.
###### Types
- Metadata
###### Functions
- get
_Type_
`ts`
type Metadata = {
/**
* The id of the client agent managing this proxy.
*/
clientAgentId: string;
/**
* The path to the value in the original object.
*/
objectPath: string[];
};
Contains information about a proxy object.
`ts`
function get
Returns metadata about a proxy. If the object is not a proxy it returns null.
##### Example
`ts
import * as Metadata from "@daniel-nagy/transporter/Metadata";
const metadata = Metadata.get(obj);
`
_Module_
The Observable module provides ReactiveX APIs similar to rxjs. If you make heavy use of Observables then you may decide to use rxjs instead.
Transporter observables should have interop with rxjs observables. If you encounter issues transforming to or from rxjs observables then you may report those issues.
Transporter operators may behave differently than rxjs operators of the same name.
###### Types
- BufferOverflowError
- BufferOverflowStrategy
- BufferOptions
- EmptyError
- Event
- EventTarget
- Observable
- ObservableLike
- Observer
- Operator
- Subscription
- State
- TimeoutError
###### Constructors
- cron
- fail
- from
- fromEvent
- of
###### Methods
###### Functions
- bufferUntil
- catchError
- filter
- firstValueFrom
- flatMap
- map
- merge
- take
- takeUntil
- tap
- timeout
- toObserver
#### BufferOverflowError
_Type_
`ts`
class BufferOverflowError extends Error {}
Thrown if a buffer overflow occurs and the buffer overflow strategy is Error.
#### BufferOverflowStrategy
_Type_
`ts`
enum BufferOverflowStrategy {
/**
* Discard new values as they arrive.
*/
DropLatest = "DropLatest",
/**
* Discard old values making room for new values.
*/
DropOldest = "DropOldest",
/**
* Error if adding a new value to the buffer will cause an overflow.
*/
Error = "Error"
}
Specifies what to do in the event of a buffer overflow.
#### BufferOptions
_Type_
`tsInfinity
type BufferOptions = {
/**
* The max capacity of the buffer. The default is .Error
*/
limit?: number;
/**
* How to handle a buffer overflow scenario. The default is .`
*/
overflowStrategy?: BufferOverflowStrategy;
};
Options for operators that perform buffering.
#### EmptyError
_Type_
`ts`
class EmptyError extends Error {}
May be thrown by operators that expect a value to be emitted if the observable completes before emitting a single value.
#### Event
_Type_
`ts`
interface Event {
type: string;
}
Represents a JavaScript event. Necessary since Transporter does not include types for a specific runtime.
#### EventTarget
_Type_
`ts`
interface EventTarget {
addEventListener(type: string, callback: (event: Event) => void): void;
dispatchEvent(event: Event): boolean;
removeEventListener(type: string, callback: (event: Event) => void): void;
}
Represents a JavaScript event target. Necessary since Transporter does not include types for a specific runtime.
_Type_
`ts`
class Observable
Observables are lazy push data structures that can emit values both synchronously and asynchronously. Observables are unicast and, unlike promises, may never emit a value or may emit many values.
#### ObservableLike
_Type_
`ts`
interface ObservableLike
subscribe(observerOrNext?: Observer
}
A value is ObservableLike if it has a subscribe method that takes a function or Observer as input and returns a Subscription.
#### Observer
_Type_
`ts`
type Observer
next?(value: T): void;
error?(error: unknown): void;
complete?(): void;
};
An Observer subscribes to an observable.
#### Operator
_Type_
`ts`
type Operator
An Operator is a function that takes an observable as input and returns a new observable as output.
#### Subscription
_Type_
`ts`
type Subscription = {
unsubscribe(): void;
};
A Subscription is returned when an observer subscribes to an observable.
#### State
_Type_
`ts`
enum State {
Complete = "Complete",
Error = "Error",
NotComplete = "NotComplete",
Unsubscribed = "Unsubscribed"
}
A discriminated type for the different states of an observable.
#### TimeoutError
_Type_
`ts`
class TimeoutError extends Error {}
Thrown by the timeout operator if a value is not emitted within the specified amount of time.
#### Cron
_Constructor_
`ts`
function cron
interval: number,
callback: () => T | Promise
): Observable
Creates an observable that calls a function at a regular interval and emits the value returned by that function.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.cron(1000, () => Math.random()).subscribe(console.log);
`
#### Fail
_Constructor_
`ts`
function fail
Creates an observable that will immediately error with the provided value. If the value is a function then the function will be called to get the value.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.fail("💩");
`
#### From
_Constructor_
`ts`
function from
Creates a new Observable from an object that is observable like or promise like.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.from(Promise.resolve("👍"));
`
#### FromEvent
_Constructor_
`ts`
function function fromEvent
Creates a hot observable from an event target and an event type.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.fromEvent(button, "click");
`
_Constructor_
`ts`
function of
Creates a new Observable that emits each argument synchronously and then completes.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).subscribe(console.log);
`
#### Pipe
_Method_
`ts`
pipe(
...operations: [Operator, ..., Operator
): Observable
Allows chaining operators to perform flow control.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, "2", 3, 4.5).pipe(
filter(Number.isInteger),
map((num) => num * 2)
);
`
#### Subscribe
_Method_
`ts`
subscribe(observerOrNext?: Observer
Causes an Observer to start receiving values from an observable as they are emitted.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).subscribe(console.log);
`
#### BufferUntil
_Function_
`ts`
function bufferUntil
signal: ObservableLike,
options?: BufferOptions
): (observable: ObservableLike
Buffers emitted values until a signal emits or completes. Once the signal emits or completes the buffered values will be emitted synchronously.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
import * as Subject from "@daniel-nagy/transporter/Subject";
const signal = Subject.init();
Observable.of(1, 2, 3).pipe(bufferUntil(signal)).subscribe(console.log);
setTimeout(() => signal.next(), 2000);
`
#### CatchError
_Function_
`ts`
function catchError
callback:
): (observable: ObservableLike
Catches an error emitted by an upstream observable. The callback function can return a new observable to recover from the error. The new observable will completely replace the old one.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3)
.pipe(
Observable.flatMap(() => Observable.fail("💩")),
Observable.catchError(() => Observable.of(4, 5, 6))
)
.subscribe(console.log);
`
#### Filter
_Function_
`ts`
function filter
callback: ((value: T) => value is S) | ((value: T) => boolean)
): (observable: ObservableLike;
Selectively keeps values for which the callback returns true. All other values are discarded.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3)
.pipe(Observable.filter((num) => num % 2 === 0))
.subscribe(console.log);
`
#### FirstValueFrom
_Function_
`ts`
function firstValueFrom
Transforms an observable into a promise that resolves with the first emitted value from the observable. If the observable errors the promise is rejected. If the observable completes without ever emitting a value the promise is rejected with an EmptyError.
WARNING
If the observable never emits the promise will never resolve.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
await Observable.firstValueFrom(Observable.of(1, 2, 3));
`
#### FlatMap
_Function_
`ts`
function flatMap
callback: (value: T) => ObservableLike | PromiseLike
): (observable: ObservableLike
Calls the callback function for each value emitted by the observable. The callback function returns a new observable that is flattened to avoid creating an observable of observables.
The observable completes when the source observable and all inner observables complete.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).pipe(
Observable.flatMap((num) => Observable.of(num * 2))
);
`
#### Map
_Function_
`ts`
function map
callback: (value: T) => U
): (observable: ObservableLike
Calls the callback function for each value emitted by the observable and emits the value returned by the callback function.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).pipe(Observable.map((num) => num * 2));
`
#### Merge
_Function_
`ts`
function merge
Merges 2 or more observables into a single observable. The resulting observable does not complete until all merged observables complete.
Values will be emitted synchronously from each observable in the order provided. Any asynchronous values will be emitted in the order they arrive.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.merge(Observable.of(1, 2, 3), Observable.of(4, 5, 6)).subscribe(
console.log
);
`
#### Take
_Function_
`ts`
function take(
amount: number
):
Takes the first n values from an observable and then completes.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).pipe(Observable.take(2)).subscribe(console.log);
`
#### TakeUntil
_Function_
`ts`
function takeUntil(
signal: ObservableLike
):
Takes values from an observable until a signal emits or completes.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
import * as Subject from "@daniel-nagy/transporter/Subject";
const signal = Subject.init();
Observable.cron(1000, () => Math.random()).pipe(Observable.takeUntil(signal));
setTimeout(() => signal.next(), 2000);
`
#### Tap
_Function_
`ts`
function tap
callback: (value: T) => unknown
):
Allows performing effects when a value is emitted without altering the value that is emitted.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.of(1, 2, 3).pipe(Observable.tap(console.log)).subscribe();
`
#### Timeout
_Function_
`ts`
function timeout
milliseconds: number,
callback?: (error: TimeoutError) => ObservableLike
):
Causes an observable to error if a value is not emitted within the specified timeout limit. The timer resets every time a value is emitted.
The callback function may return a new observable to replace the old one or to return a specific error.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
Observable.cron(1000, () => Math.random())
.pipe(Observable.timeout(999))
.subscribe();
`
#### ToObserver
_Function_
`ts`
function toObserver
observerOrNext?: Observer
): Observer
Takes a value that may be an observer or a function and returns an observer. If called without an argument it will return an empty object.
##### Example
`ts
import * as Observable from "@daniel-nagy/transporter/Observable";
const identity = (value) => value;
const observer = toObserver(identity);
`
_Module_
The Proxy module is used to create proxy objects. Transporter will proxy these objects instead of cloning them.
###### Types
- Proxy
###### Constructors
- from
###### Functions
- isProxy
_Type_
`ts`
type Proxy
JsObject.PickDeep
>;
A Proxy is a readonly object who's properties are functions.
_Constructor_
`ts`
function from
Creates a proxy from any object. The resulting object will be readonly and only
functions will remain as properties.
##### Example
`ts
import * as Proxy from "@daniel-nagy/transporter/Proxy";
const proxy = Proxy.from({
a: "a",
b: async () => "👍",
c: [12, async () => "👌"]
});
// $ExpectType
// {
// readonly b: async () => "👍",
// readonly c: {
// readonly 1: async () => "👌"
// }
// }
`
#### IsProxy
_Function_
`ts`
function isProxy
Returns true if the object is a Proxy.
##### Example
`ts
import * as Proxy from "@daniel-nagy/transporter/Proxy";
const proxy = Proxy.from({
b: async () => "👍"
});
Proxy.isProxy(proxy); // true
`
_Module_
The PubSub module is used to wrap an Observable so that it may be used for pub/sub. A PubSub is essentially an Observable who's subscribe and unsubscribe methods are asynchronous.
###### Types
- AsyncObserver
- PubSub
- RemoteSubscription
###### Constructors
- from
#### AsyncObserver
_Type_
`ts`
type AsyncObserver
next?(value: T): Promise
error?(error: unknown): Promise
complete?(): Promise
};
An Observer who's methods are asynchronous.
_Type_
`ts`
interface PubSub
subscribe(
observerOrNext: AsyncObserver
): Promise
}
An Observable who's subscribe method is asynchronous.
#### RemoteSubscription
_Type_
`ts`
type RemoteSubscription = {
unsubscribe(): Promise
};
A Subscription that returns a promise when unsubscribed.
_Constructor_
`ts`
function from
Turns an ordinary observable into an asynchronous one.
##### Example
`ts
import * as PubSub from "@daniel-nagy/transporter/PubSub";
const pubSub = PubSub.from(Observable.of(1, 2, 3));
`
_Module_
The Session module is used to create client and server sessions.
###### Types
- Agent
- ClientOptions
- ClientSession
- Resource
- ServerOptions
- ServerSession
- Session
###### Constants
###### Constructors
###### Methods
#### Agent
_Type_
`ts`
type Agent = ClientAgent.t | ServerAgent.t;
An Agent is a background task that manages a single resource and fulfills the
Transporter protocol.
#### ClientOptions
_Type_
`ts`
interface ClientOptions
injector?: Injector.t;
protocol: Subprotocol
resource: Resource
}
Options for creating a ClientSession.
#### ClientSession
_Type_
`ts`
class ClientSession
createProxy(): Proxy.t
}
A ClientSession is created on the client to proxy a remote resource.
#### Resource
_Type_
`ts`
interface Resource
A Resource is a value that is provided by a server.
#### ServerOptions
_Type_
`ts`
interface ServerOptions
injector?: Injector.t;
protocol: Subprotocol
provide: Value;
}
Options for creating a ServerSession.
#### ServerSession
_Type_
`ts`
class ServerSession
A ServerSession is created on the server to provide a resource.
_Type_
`ts`
abstract class Session
readonly injector?: Injector.t;
readonly input: Observable.Observer
readonly output: Observable.t
readonly protocol: Subprotocol
}
A Session spawns and observes agents. A session may spawn multiple server or client agents while active. Terminating a session will terminate all agents spawned by the session that are still active.
If all agents spawned by the session are terminated then the session is automatically terminated.
#### RootSupervisor
_Constant_
`ts`
const rootSupervisor = Supervisor.init
The root supervisor observers all active sessions.
_Constructor_
`ts`
const Resource =
Creates a new Resource. This container type is necessary because TypeScript
lacks partial inference of type parameters.
`ts
import * as Session from "@daniel-nagy/transporter/Session";
import type { Api } from "...";
const resource = Session.Resource
`
#### Client
_Constructor_
`ts`
function client
options: ClientOptions
): ClientSession
Creates a new ClientSession.
##### Example
`ts
import * as Session from "@daniel-nagy/transporter/Session";
import * as Subprotocol from "@daniel-nagy/transporter/Subprotocol";
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
import type { Api } from "...";
const httpProtocol = Subprotocol.init({
connectionMode: Subprotocol.ConnectionMode.ConnectionLess,
dataType: Subprotocol.DataType
operationMode: Subprotocol.OperationMode.Unicast,
transmissionMode: Subprotocol.TransmissionMode.HalfDuplex
});
const session = Session.client({
protocol: httpProtocol,
resource: Session.Resource
});
const client = session.createProxy();
`
#### Server
_Constructor_
`ts`
function server
options: ServerOptions
): ServerSession
Creates a new ServerSession.
##### Example
`ts
import * as Session from "@daniel-nagy/transporter/Session";
import * as Subprotocol from "@daniel-nagy/transporter/Subprotocol";
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
module User {
export async greet = () => "👋"
}
const httpProtocol = Subprotocol.init({
connectionMode: Subprotocol.ConnectionMode.ConnectionLess,
dataType: Subprotocol.DataType
operationMode: Subprotocol.OperationMode.Unicast,
transmissionMode: Subprotocol.TransmissionMode.HalfDuplex
});
const session = Session.server({
protocol: httpProtocol,
provide: {
User
}
});
`
#### Terminate
_Method_
`ts`
terminate(): void;
Terminates the session. Terminating the session will complete its input and output and terminate all currently active agents.
_Module_
A Subject can be used to multicast an Observable.
###### Types
- Subject
###### Constructors
- init
###### Methods
- asObservable
- complete
- error
- next
- subscribe
_Type_
`ts`
class Subject
implements Observable.ObservableLike
A Subject is both an Observable and an Observer.
_Constructor_
`ts`
function init
Creates a new Subject.
##### Example
`ts
import * as Subject from "@daniel-nagy/transporter/Subject";
const subject = Subject.init
`
#### AsObservable
_Method_
`ts`
asObservable(): Observable.t
Transforms the subject into a hot observable.
#### Complete
_Method_
`ts`
complete(): void;
Changes the subject's state to Complete.
_Method_
`ts`
error(error: unknown): void;
Changes the subject's state to Error.
#### Next
_Method_
`ts`
next(value: T): void;
Emits the value to all subscribers.
_Method_
`ts`
subscribe(
observerOrNext?: Observable.Observer
): Observable.Subscription;
Subscribes to state changes and values emitted by the subject.
_Module_
The Transporter protocol is type agnostic. In order to provide type-safety a subprotocol is required. The subprotocol restricts what types may be included in function IO. For example, if the data type of a subprotocol is JSON then only JSON data types may be input or output from remote functions.
In addition, Transporter can perform recursive RPC if certain subprotocol and network conditions are met. Recursive RPC means functions or proxies may be included in function IO. This is an interesting concept because it allows state between processes to be held on the call stack. For example, recursive RPC allows Observables to be used for pub-sub.
In order to use recursive RPC your subprotocol must be connection-oriented and bidirectional. If those conditions are met then the call signature for remote functions will allow functions or proxies as input or output. It turns out that these types of connections are common in the browser.
###### Types
- ConnectionMode
- DataType
- OperationMode
- Subprotocol
- TransmissionMode
###### Constructors
###### Functions
#### ConnectionMode
_Type_
`ts`
enum ConnectionMode {
/**
* A message can be sent from one endpoint to another without prior
* arrangement. For example, HTTP is a connectionless protocol.
*/
Connectionless = "Connectionless",
/**
* A session or connection is established before data can be transmitted. For
* example, TCP is a connection-oriented protocol.
*/
ConnectionOriented = "ConnectionOriented"
}
Used to define the type of connection between the client and the server.
_Type_
`ts`
interface DataType
Constrains the input and output types of a procedure to a specific data type.
#### OperationMode
_Type_
`ts`
enum OperationMode {
/**
* A single message is sent to every node in a network. This is a one-to-all
* transmission.
*/
Broadcast = "Broadcast",
/**
* A single message is sent to a subset of nodes in a network. This is a
* one-to-many transmission.
*/
Multicast = "Multicast",
/**
* A single message is sent to a single node. This is a one-to-one
* transmission.
*/
Unicast = "Unicast"
}
Used to define how data is distributed to nodes in a network.
_Type_
`ts`
interface Subprotocol
Used to restrict function input and output types as well as determine if recursive RPC can be enabled or not.
#### TransmissionMode
_Type_
`ts`
enum TransmissionMode {
/**
* Either side may transmit data at any time. This is a 2-way communication.
*/
Duplex = "Duplex",
/**
* Only one side can transmit data at a time. This is a 2-way communication.
*/
HalfDuplex = "HalfDuplex",
/**
* Only the sender can transmit data. This is a 1-way communication.
*/
Simplex = "Simplex"
}
Used to define how data is transmitted over a network.
_Constructor_
`ts`
function DataType
Creates a new DataType.
##### Example
`ts
import * as Json from "@daniel-nagy/transporter/Json";
import * as Subprotocol from "@daniel-nagy/transporter/Subprotocol";
const jsonDataType = Subprotocol.DataType
`
_Constructor_
`ts`
function init(options: {
connectionMode: ConnectionMode;
dataType: DataType;
operationMode: OperationMode;
transmissionMode: TransmissionMode;
}): Subprotocol;
Creates a new Subprotocol.
##### Example
`ts
import * as Subprotocol from "@daniel-nagy/transporter/Subprotocol";
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
const subprotocol = Subprotocol.init({
connectionMode: Session.ConnectionMode.ConnectionLess,
dataType: Subprotocol.DataType
operationMode: Session.OperationMode.Unicast,
transmissionMode: Session.TransmissionMode.HalfDuplex
});
`
#### IsBidirectional
_Function_
`ts`
function isBidirectional(protocol: Subprotocol
Returns true is the subprotocol is bidirectional. The connection is considered bidirectional if its operation mode is unicast and its transmission mode is duplex or half-duplex.
##### Example
`ts
import * as Subprotocol from "@daniel-nagy/transporter/Subprotocol";
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
const subprotocol = Subprotocol.init({
connectionMode: Session.ConnectionMode.ConnectionLess,
dataType: Subprotocol.DataType
operationMode: Session.OperationMode.Unicast,
transmissionMode: Session.TransmissionMode.HalfDuplex
});
Subprotocol.isBidirectional(subprotocol); // true
`
_Module_
The SuperJson module extends JSON to include many built-in JavaScript types, including Date, RegExp, Map, ect.
###### Types
###### Functions
_Type_
`ts`
type SuperJson =
| void
| null
| undefined
| boolean
| number
| bigint
| string
| Date
| RegExp
| Array
| Map
| Set
| { [key: string]: SuperJson };
An extended JSON type that includes many builtin JavaScript types.
#### FromJson
_Function_
`ts`
function fromJson(value: Json.t): SuperJson;
Revives an encoded SuperJson value from a JSON value.
##### Example
`ts
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
SuperJson.fromJson(value);
`
#### ToJson
_Function_
`ts`
function toJson(value: SuperJson): Json.t;
Encodes a SuperJson value as a valid JSON value.
##### Example
`ts
import * as SuperJson from "@daniel-nagy/transporter/SuperJson";
SuperJson.toJson(new Date());
``