@polywrap/core-js
A TypeScript / JavaScript implementation of the WRAP standard, including all fundamental types & algorithms.
Reference
Types
CoreClient
/** Core Client configuration that can be passed to the PolywrapClient or PolywrapCoreClient constructors */
export interface CoreClientConfig {
/** register interface implementations */
readonly interfaces?: ReadonlyUriMap<readonly Uri[]>;
/** set environmental variables for a wrapper */
readonly envs?: ReadonlyUriMap<WrapperEnv>;
/** configure URI resolution for redirects, packages, and wrappers */
readonly resolver: Readonly<IUriResolver<unknown>>;
}
/** Options for CoreClient's getFile method */
export interface GetFileOptions {
/** file path from wrapper root */
path: string;
/** file encoding */
encoding?: "utf-8" | string;
}
/** Options for CoreClient's getImplementations method */
export interface GetImplementationsOptions {
/** If true, follow redirects to resolve URIs */
applyResolution?: boolean;
/** Use and update an existing resolution context */
resolutionContext?: IUriResolutionContext;
}
/** Options for CoreClient's validate method */
export interface ValidateOptions {
/** Validate full ABI */
abi?: boolean;
/** Recursively validate import URIs */
recursive?: boolean;
}
/** CoreClient invokes wrappers and interacts with wrap packages. */
export interface CoreClient extends Invoker, UriResolverHandler<unknown> {
/**
* Returns the configuration used to instantiate the client
*
* @returns an immutable core client config
*/
getConfig(): CoreClientConfig;
/**
* returns all interfaces from the configuration used to instantiate the client
*
* @returns a Set of interfaces and their registered implementations
*/
getInterfaces(): ReadonlyUriMap<readonly Uri[]> | undefined;
/**
* returns all env registrations from the configuration used to instantiate the client
*
* @returns an array of env objects containing wrapper environmental variables
*/
getEnvs(): ReadonlyUriMap<WrapperEnv> | undefined;
/**
* returns an env (a set of environmental variables) from the configuration used to instantiate the client
*
* @param uri - the URI used to register the env
* @returns an env, or undefined if an env is not found at the given URI
*/
getEnvByUri(uri: Uri): WrapperEnv | undefined;
/**
* returns the URI resolver from the configuration used to instantiate the client
*
* @returns an object that implements the IUriResolver interface
*/
getResolver(): IUriResolver<unknown>;
/**
* returns a package's wrap manifest
*
* @param uri - a wrap URI
* @returns a Result containing the WrapManifest if the request was successful
*/
getManifest(uri: Uri): Promise<Result<WrapManifest, WrapError>>;
/**
* returns a file contained in a wrap package
*
* @param uri - a wrap URI
* @param options - { path: string; encoding?: "utf-8" | string }
* @returns a Promise of a Result containing a file if the request was successful
*/
getFile(
uri: Uri,
options: GetFileOptions
): Promise<Result<string | Uint8Array, WrapError>>;
/**
* returns the interface implementations associated with an interface URI
* from the configuration used to instantiate the client
*
* @param uri - a wrap URI
* @param options - { applyResolution?: boolean; resolutionContext?: IUriResolutionContext }
* @returns a Result containing URI array if the request was successful
*/
getImplementations(
uri: Uri,
options: GetImplementationsOptions
): Promise<Result<Uri[], WrapError>>;
}
Env
/** A map of string-indexed, Msgpack-serializable environmental variables associated with a wrapper */
export interface WrapperEnv {
readonly [k: string]: unknown;
}
Invoke
/** Options required for an Wrapper invocation. */
export interface InvokeOptions {
/** The Wrapper's URI */
uri: Uri;
/** Method to be executed. */
method: string;
/** Arguments for the method, structured as a map, removing the chance of incorrectly ordered arguments. */
args?: Record<string, unknown> | Uint8Array;
/** Env variables for the wrapper invocation. */
env?: Record<string, unknown>;
/** A Uri resolution context */
resolutionContext?: IUriResolutionContext;
}
/**
* Result of an Wrapper invocation.
*
* @template TData Type of the invoke result data.
*/
export type InvokeResult<TData = unknown> = Result<TData, WrapError>;
/**
* Provides options for the invoker to set based on the state of the invocation.
* Extends InvokeOptions.
*/
export interface InvokerOptions extends InvokeOptions {
/** If true, the InvokeResult will (if successful) contain a Msgpack-encoded byte array */
encodeResult?: boolean;
}
/**
* An entity capable of invoking wrappers.
*
* @template TData Type of the invoke result data.
*/
export interface Invoker {
/**
* Invoke a wrapper using an instance of the wrapper.
*
* @param options - invoker options and a wrapper instance to invoke
* @returns A Promise with a Result containing the return value or an error
*/
invokeWrapper<TData = unknown>(
options: InvokerOptions & { wrapper: Wrapper }
): Promise<InvokeResult<TData>>;
/**
* Invoke a wrapper.
*
* @remarks
* Unlike `invokeWrapper`, this method automatically retrieves and caches the wrapper.
*
* @param options - invoker options
* @returns A Promise with a Result containing the return value or an error
*/
invoke<TData = unknown>(
options: InvokerOptions
): Promise<InvokeResult<TData>>;
}
/**
* Result of a Wrapper invocation, possibly Msgpack-encoded.
*
* @template TData Type of the invoke result data.
*/
export type InvocableResult<TData = unknown> = InvokeResult<TData> & {
/** If true, result (if successful) contains a Msgpack-encoded byte array */
encoded?: boolean;
};
/** An invocable entity, such as a wrapper. */
export interface Invocable {
/**
* Invoke this object.
*
* @param options - invoke options
* @param invoker - an Invoker, capable of invoking this object
* @returns A Promise with a Result containing the return value or an error
*/
invoke(
options: InvokeOptions,
invoker: Invoker
): Promise<InvocableResult<unknown>>;
}
IUriPackage
/** Associates a URI with an embedded wrap package */
export interface IUriPackage {
/** The package's URI */
uri: Uri;
/** The wrap package */
package: IWrapPackage;
}
IUriRedirect
/** Redirect invocations from one URI to another */
export interface IUriRedirect {
/** URI to redirect from */
from: Uri;
/** URI to redirect to */
to: Uri;
}
IUriWrapper
/** Associates a URI with an embedded wrapper */
export interface IUriWrapper {
/** The URI to resolve to the wrapper */
uri: Uri;
/** A wrapper instance */
wrapper: Wrapper;
}
IWrapPackage
/** Options for IWrapPackage's getManifest method */
export interface GetManifestOptions {
/** If true, manifest validation step will be skipped */
noValidate?: boolean;
}
/** A wrap package, capable of producing instances of a wrapper and its manifest */
export interface IWrapPackage {
/**
* Produce an instance of the wrap manifest
*
* @param options - GetManifestOptions; customize manifest retrieval
* @returns A Promise with a Result containing the wrap manifest or an error
*/
getManifest(
options?: GetManifestOptions
): Promise<Result<WrapManifest, Error>>;
/**
* Produce an instance of the wrapper
*
* @param options - DeserializeManifestOptions; customize manifest deserialization
* @returns A Promise with a Result containing the wrapper or an error
*/
createWrapper(
options?: DeserializeManifestOptions
): Promise<Result<Wrapper, Error>>;
}
MaybeAsync
/** Alias for a type that is either a value or a promise that resolves to the value */
export type MaybeAsync<T> = Promise<T> | T;
Uri
UriConfig
/** URI configuration */
export interface UriConfig {
/** URI Authority: allows the Polywrap URI resolution algorithm to determine an authoritative URI resolver. */
authority: string;
/** URI Path: tells the Authority where the Wrapper resides. */
path: string;
/** Full string representation of URI */
uri: string;
}
Uri
/**
* A Polywrap URI. Some examples of valid URIs are:
* wrap://https/domain.com
* wrap://ipfs/QmHASH
* wrap://wrapscan.io/polywrap/wrap@1.2.3
* wrap://ens/sub.domain.eth
* wrap://file/directory/file.txt
*
* Some example short-hand URIs (utilizing inference):
* ipfs/QmHASH -> wrap://ipfs/QmHASH
* https://domain.com -> wrap://https/domain.com
*
* URI inference is performed in the following ways:
* 1. If wrap:// is missing, it will be added.
* 2. If non-wrap schema exists, it becomes the authority.
*
* Breaking down the various parts of the URI, as it applies
* to [the URI standard](https://tools.ietf.org/html/rfc3986#section-3):
* **wrap://** - URI Scheme: differentiates Polywrap URIs.
* **wrapscan.io/** - URI Authority: allows the Polywrap URI resolution algorithm to determine an authoritative URI resolver.
* **polywrap/wrap@1.2.3** - URI Path: tells the Authority where the Wrapper resides.
*/
export class Uri {
constructor
/**
* Construct a Uri instance from a wrap URI string
*
* @remarks
* Throws if URI string is invalid
*
* @param uri - a string representation of a wrap URI
*/
constructor(uri: string)
authority
/** @returns Uri authority */
public get authority(): string
path
/** @returns Uri path */
public get path(): string
uri
/** @returns Uri string representation */
public get uri(): string
equals
/** Test two Uri instances for equality */
public static equals(a: Uri, b: Uri): boolean
isUri
/**
* Check if a value is an instance of Uri
*
* @param value - value to check
* @returns true if value is a Uri instance */
public static isUri(value: unknown): value is Uri
isValidUri
/**
* Test if a URI string is a valid wrap URI
*
* @param uri - URI string
* @param parsed? - UriConfig to update (mutate) with content of URI string
* @returns true if input string is a valid wrap URI */
public static isValidUri(uri: string, parsed?: UriConfig): boolean
toString
/** @returns Uri string representation */
public toString(): string
toJSON
/** @returns Uri string representation */
public toJSON(): string
parseUri
/**
* Parse a wrap URI string into its authority and path
*
* @param uri - a string representation of a wrap URI
* @returns A Result containing a UriConfig, if successful, or an error
*/
public static parseUri(input: string): Result<UriConfig, Error>
from
/**
* Construct a Uri instance from a Uri or a wrap URI string
*
* @remarks
* Throws if URI string is invalid
*
* @param uri - a Uri instance or a string representation of a wrap URI
*/
public static from(uri: Uri | string): Uri
UriResolver
/** Options required for URI resolution. */
export interface TryResolveUriOptions {
/** The Wrapper's URI */
uri: Uri;
/** A URI resolution context */
resolutionContext?: IUriResolutionContext;
}
/** An entity capable of resolving a wrap URI, typically by using an IUriResolver implementation */
export interface UriResolverHandler<TError = undefined> {
/**
* Resolve a URI to a wrap package, a wrapper, or a uri
*
* @param options - TryResolveUriOptions
* @returns A Promise with a Result containing either a wrap package, a wrapper, or a URI if successful
*/
tryResolveUri(
options?: TryResolveUriOptions
): Promise<Result<UriPackageOrWrapper, TError>>;
}
Wrapper
/**
* The Wrapper definition, which can be used to spawn
* many invocations of this particular Wrapper. Internally
* this class may do things like caching WASM bytecode, spawning
* worker threads, or indexing into resolvers to find the requested method.
*/
export interface Wrapper extends Invocable {
/**
* Invoke the Wrapper based on the provided [[InvokeOptions]]
*
* @param options Options for this invocation.
* @param invoker The client instance requesting this invocation.
* This client will be used for any sub-invokes that occur.
*/
invoke(
options: InvokeOptions,
invoker: Invoker
): Promise<InvocableResult<unknown>>;
/**
* Get a file from the Wrapper package.
*
* @param options Configuration options for file retrieval
*/
getFile(options: GetFileOptions): Promise<Result<Uint8Array | string, Error>>;
/**
* Get a manifest from the Wrapper package.
*/
getManifest(): WrapManifest;
}
UriResolverInterface
MaybeUriOrManifest
/** Contains either a Uri, a manifest, or neither */
export interface MaybeUriOrManifest {
/** wrap URI */
uri?: string | null;
/** Serialized wrap manifest */
manifest?: Uint8Array | null;
}
Module
tryResolveUri
/**
* Use an invoker to try to resolve a URI using a wrapper that implements the UriResolver interface
*
* @param invoker - invokes the wrapper with the resolution URI as an argument
* @param wrapper - URI for wrapper that implements the UriResolver interface
* @param uri - the URI to resolve
*/
tryResolveUri: async (
invoker: Invoker,
wrapper: Uri,
uri: Uri
): Promise<Result<MaybeUriOrManifest, WrapError>>
getFile
/**
* Use an invoker to fetch a file using a wrapper that implements the UriResolver interface
*
* @param invoker - invokes the wrapper with the filepath as an argument
* @param wrapper - URI for wrapper that implements the UriResolver interface
* @param path - a filepath, the format of which depends on the UriResolver
*/
getFile: async (
invoker: Invoker,
wrapper: Uri,
path: string
): Promise<Result<Uint8Array | null, WrapError>>
Uri Resolution
IUriResolutionContext
/** Track and output URI resolution state, path, and history */
export interface IUriResolutionContext {
/**
* Check if a URI is in the process of being resolved
*
* @param uri - URI to check
* @return true if URI resolution is in process, false otherwise
*/
isResolving(uri: Uri): boolean;
/**
* Start resolving a URI
*
* @param uri - Uri to resolve
*/
startResolving(uri: Uri): void;
/**
* Stop resolving a URI
*
* @param uri - Uri being resolved
*/
stopResolving(uri: Uri): void;
/**
* Push a step onto the resolution history stack
*
* @param step - A completed resolution step
*/
trackStep<TError>(step: IUriResolutionStep<TError>): void;
/** @return history of all URI resolution steps completed */
getHistory(): IUriResolutionStep<unknown>[];
/** @return current URI resolution path */
getResolutionPath(): Uri[];
/**
* Create a new resolution context using the current URI resolution path
*
* @return a UriResolutionContext
*/
createSubHistoryContext(): IUriResolutionContext;
/**
* Create a new resolution context using the current URI resolution history
*
* @return a UriResolutionContext
*/
createSubContext(): IUriResolutionContext;
}
IUriResolutionStep
/** A step in the URI resolution algorithm */
export interface IUriResolutionStep<TError = undefined> {
/** The current URI being resolved */
sourceUri: Uri;
/** The resolution result for the current URI */
result: Result<UriPackageOrWrapper, TError>;
/** A text/visual description of this URI step */
description?: string;
/** History of sub-steps that exist within the context of this URI resolution step */
subHistory?: IUriResolutionStep<TError>[];
}
IUriResolver
/** Defines entity capable of resolving a wrap URI */
export interface IUriResolver<TError = undefined> {
/**
* Resolve a URI to a wrap package, a wrapper, or a uri
*
* @param uri - the URI to resolve
* @param client - a CoreClient instance that may be used to invoke a wrapper that implements the UriResolver interface
* @param resolutionContext - the current URI resolution context
* @returns A Promise with a Result containing either a wrap package, a wrapper, or a URI if successful
*/
tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError>>;
}
UriPackageOrWrapper
/** Indicates that a URI resolved to a Uri */
export type UriValue = {
type: "uri";
uri: Uri;
};
/** Indicates that a URI resolved to a wrap package */
export type UriPackageValue = IUriPackage & {
type: "package";
};
/** Indicates that a URI resolved to a wrapper */
export type UriWrapperValue = IUriWrapper & {
type: "wrapper";
};
/** indicates that a URI resolved to either a wrap package, a wrapper, or a URI */
export type UriPackageOrWrapper = UriValue | UriPackageValue | UriWrapperValue;
UriResolutionContext
/** An implementation of the IUriResolutionContext interface */
export class UriResolutionContext implements IUriResolutionContext {
constructor
/** Construct a UriResolutionContext */
constructor();
constructor(
resolvingUriMap: Map<string, boolean>,
resolutionPath: Set<string>
);
constructor(
resolvingUriMap: Map<string, boolean>,
history: IUriResolutionStep<unknown>[]
);
constructor(
resolvingUriMap?: Map<string, boolean>,
resolutionPathOrHistory?: Set<string> | IUriResolutionStep<unknown>[]
)