@polywrap/uri-resolvers
URI resolvers to customize URI resolution in the Polywrap Client.
Installation
npm install --save @polywrap/uri-resolvers-js
Usage
This example is similar to the default resolver used by the PolywrapClientConfigBuilder in the @polywrap/client-config-builder-js package.
const resolver = RecursiveResolver.from(
WrapperCacheResolver.from(
[
StaticResolver.from([
...redirects,
...wrappers,
...packages,
]),
],
new WrapperCache()
)
);
Reference
UriResolverAggregatorBase
/**
* Abstract class for IUriResolver implementations that aggregate multiple resolvers.
* The UriResolverAggregatorBase class attempts to resolve a URI by sequentially
* attempting resolution with each of its composite resolvers.
* */
export abstract class UriResolverAggregatorBase<
TResolutionError = undefined,
TGetResolversError = undefined
> implements IUriResolver<TResolutionError | TGetResolversError>
Methods
getUriResolvers
/**
* Get a list of URI Resolvers
*
* @param uri - the URI to query for resolvers
* @param client - a CoreClient instance that can be used to make an invocation
* @param resolutionContext - a resolution context to update when resolving URIs
*
* @returns a list of IUriResolver or an error
* */
abstract getUriResolvers(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<IUriResolver<unknown>[], TGetResolversError>>;
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* Attempts to resolve the URI using each of the aggregated resolvers sequentially.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<
Result<UriPackageOrWrapper, TResolutionError | TGetResolversError>
>
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @param uri - the URI being resolved
* @param result - the result of a resolution attempt
*
* @returns text describing the URI resolution step
* */
protected abstract getStepDescription(
uri: Uri,
result: Result<UriPackageOrWrapper, TResolutionError>
): string;
tryResolveUriWithResolvers (protected)
/**
* Using each of the aggregated resolvers, attempt to resolve a URI
*
* @param uri - the URI to resolve
* @param client - a CoreClient instance that can be used to make an invocation
* @param resolvers - a list of IUriResolver implementations
* @param resolutionContext - a resolution context to update when resolving URIs
*
* @returns a URI, a Wrap Package, or a Wrapper (or an error)
* */
protected async tryResolveUriWithResolvers(
uri: Uri,
client: CoreClient,
resolvers: IUriResolver<unknown>[],
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TResolutionError>>
UriResolverAggregator
/**
* An implementation of UriResolverAggregatorBase
*/
export class UriResolverAggregator<
TResolutionError = undefined,
TGetResolversError = undefined
> extends UriResolverAggregatorBase<
TResolutionError,
TGetResolversError
>
Types
GetResolversFunc
/**
* A function that returns a list of resolvers
*
* @param uri - the URI to query
* @param client - a CoreClient instance
* */
export type GetResolversFunc = (
uri: Uri,
client: CoreClient
) => Promise<IUriResolver<unknown>[]>;
GetResolversWithErrorFunc
/**
* A function that returns a list of resolvers or an error
*
* @param uri - the URI to query
* @param client - a CoreClient instance
* */
export type GetResolversWithErrorFunc<TError> = (
uri: Uri,
client: CoreClient
) => Promise<Result<IUriResolver<unknown>[], TError>>;
Methods
constructor
/**
* Creates a UriResolverAggregator from a list of resolvers, or from a function
* that returns a list of resolvers
* */
constructor(resolvers: UriResolverLike[], resolverName?: string);
constructor(
resolvers: (
uri: Uri,
client: CoreClient
) => Promise<Result<IUriResolver<unknown>[], TGetResolversError>>,
resolverName?: string
);
constructor(resolvers: GetResolversFunc, resolverName?: string);
constructor(
resolvers:
| UriResolverLike[]
| GetResolversFunc
| GetResolversWithErrorFunc<TGetResolversError>,
private _resolverName?: string
)
getUriResolvers
/**
* Get a list of URI Resolvers
*
* @param uri - the URI to query for resolvers
* @param client - a CoreClient instance that can be used to make an invocation
*
* @returns a list of IUriResolver or an error
* */
async getUriResolvers(
uri: Uri,
client: CoreClient
): Promise<Result<IUriResolver<unknown>[], TGetResolversError>>
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @returns text describing the URI resolution step
* */
protected getStepDescription = (): string
IWrapperCache
/** A Wrapper cache */
export interface IWrapperCache {
/** get a Wrapper from the cache, given its URI index */
get(uri: Uri): MaybeAsync<Wrapper | undefined>;
/** add a Wrapper to the cache, indexed by a URI */
set(uri: Uri, wrapper: Wrapper): MaybeAsync<void>;
}
WrapperCache
/**
* A minimal implementation of IWrapperCache
* */
export class WrapperCache implements IWrapperCache
Methods
get
/** get a Wrapper from the cache, given its URI index */
get(uri: Uri): Wrapper | undefined
set
/** add a Wrapper to the cache, indexed by a URI */
set(uris: Uri, wrapper: Wrapper): void
WrapperCacheResolver
/**
* An IUriResolver implementation that caches wrappers once they are resolved.
* As it is a wrapper cache resolver, URI and package caching is outside of the scope for this resolver
* and can be achieved through other resolvers if necessary.
* The WrapperCacheResolver wraps an IUriResolver implementation and delegates resolution to it.
* */
export class WrapperCacheResolver<TError>
implements IUriResolver<TError | Error>
constructor
/**
* Creates a WrapperCacheResolver
*
* @param _innerResolver - a resolver to delegate resolution to
* @param _cache - a wrapper cache
* */
constructor(
private _innerResolver: IUriResolver<TError>,
private _cache: IWrapperCache
)
Methods
from
/**
* Creates a WrapperCacheResolver from a resolver-like object
*
* @param innerResolver - a resolver-like item to delegate resolution to
* @param cache - a wrapper cache
* @param options - control wrapper manifest deserialization
*
* @returns a WrapperCacheResolver
* */
static from<TResolverError = unknown>(
innerResolver: UriResolverLike,
cache: IWrapperCache
): WrapperCacheResolver<TResolverError>
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* If successful, cache the result.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError | Error>>
getUriResolutionPath
/**
* Get a resolution path from the history of a URI resolution attempt
*
* @param history - the resolution context
* @returns the URI's resolution path
* */
export const getUriResolutionPath = (
history: IUriResolutionStep<unknown>[]
): IUriResolutionStep<unknown>[]
InfiniteLoopError
/**
* Error used if the URI resolution path contains an infinite loop
* */
export class InfiniteLoopError extends Error
constructor
/**
* Create an InfiniteLoopError
*
* @param _uri - URI being resolved
* @param _history - URI resolution history
* */
constructor(
private readonly _uri: Uri,
private readonly _history: IUriResolutionStep<unknown>[]
)
ResolverWithHistory
/** An abstract IUriResolver implementation that updates the resolution context */
export abstract class ResolverWithHistory<TError = undefined>
implements IUriResolver<TError>
Methods
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* Updates the resolution context with the result.
*
* @remarks
* This method calls the internal abstract method _tryResolveUri before
* updating the resolution context. Implementations are expect to place
* resolution logic in _tryResolveUri.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError>>
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @param uri - the URI being resolved
* @param result - the result of a resolution attempt
*
* @returns text describing the URI resolution step
* */
protected abstract getStepDescription(
uri: Uri,
result: Result<UriPackageOrWrapper, TError>
): string;
_tryResolveUri (protected)
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* Updates the resolution context with the result.
*
* @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
*/
protected abstract _tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError>>;
ResolverWithLoopGuard
/** An IUriResolver implementation that prevents infinite loops in the resolution path. */
export class ResolverWithLoopGuard<TError = undefined>
implements IUriResolver<TError | InfiniteLoopError>
constructor
/**
* Construct a ResolverWithLoopGuard
*
* @param _resolver - a resolution to delegate resolution to
* */
constructor(private _resolver: IUriResolver<TError>)
Methods
from
/**
* Create a ResolverWithLoopGuard from a resolver-like object
*
* @param resolver - a resolver-like item to delegate resolution to
*
* @returns a ResolverWithLoopGuard
* */
static from<TResolverError = unknown>(
resolver: UriResolverLike
): ResolverWithLoopGuard<TResolverError>
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* Ensures the URI is not caught in an infinite loop by checking if it is already resolving.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError | InfiniteLoopError>>
PackageToWrapperResolver
/**
* An IUriResolver implementation that initalizes wrappers from resolved packages.
* The PackageToWrapperResolver wraps an IUriResolver implementation and delegates resolution to it.
* */
export class PackageToWrapperResolver<TError>
implements IUriResolver<TError | Error>
constructor
/**
* Creates a PackageToWrapperResolver
*
* @param _innerResolver - a resolver to delegate resolution to
* @param _options - control wrapper manifest deserialization
* */
constructor(
private _innerResolver: IUriResolver<TError>,
private _options?: {
deserializeManifestOptions?: DeserializeManifestOptions;
}
)
Methods
from
/**
* Creates a PackageToWrapperResolver from a resolver-like object
*
* @param innerResolver - a resolver-like item to delegate resolution to
* @param options - control wrapper manifest deserialization
*
* @returns a PackageToWrapperResolver
* */
static from<TResolverError = unknown>(
innerResolver: UriResolverLike,
options?: { deserializeManifestOptions?: DeserializeManifestOptions }
): PackageToWrapperResolver<TResolverError>
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* If successful, cache the result.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError | Error>>
UriResolver
/** An IUriResolver factory */
export class UriResolver
Methods
from
/**
* Create an IUriResolver instance
*
* @param resolverLike - an object that can be transformed into a resolver
* @param resolverName - a name to assign to the resolver in resolution history output
* */
static from<TError = undefined>(
resolverLike: UriResolverLike,
resolverName?: string
): IUriResolver<TError>
UriResolverLike
/** An UriResolverLike can be one of three things:
* - An IUriResolver
* - An object that can be transformed into a static IUriResolver
* - An array of UriResolverLike
* */
export type UriResolverLike =
| IUriResolver<unknown>
| IUriRedirect
| IUriPackage
| IUriWrapper
| UriResolverLike[];
UriResolutionResult
/** Factory for creating Result from URI resolution output */
export class UriResolutionResult<TError = undefined>
Methods
ok
/** Returns a Result with `ok` set to true */
static ok<TError = undefined>(uri: Uri): Result<UriPackageOrWrapper, TError>;
static ok<TError = undefined>(
uri: Uri,
wrapPackage: IWrapPackage
): Result<UriPackageOrWrapper, TError>;
static ok<TError = undefined>(
uri: Uri,
wrapper: Wrapper
): Result<UriPackageOrWrapper, TError>;
static ok<TError = undefined>(
uriPackageOrWrapper: UriPackageOrWrapper
): Result<UriPackageOrWrapper, TError>;
static ok<TError = undefined>(
uriPackageOrWrapper: Uri | UriPackageOrWrapper,
packageOrWrapper?: IWrapPackage | Wrapper
): Result<UriPackageOrWrapper, TError>
err
/** Returns a Result with `ok` set to false */
static err<TError = unknown>(
error: TError
): Result<UriPackageOrWrapper, TError>
PackageResolver
/**
* A Uri Resolver that resolves to an embedded wrap package and correctly updates
* the resolution history.
* */
export class PackageResolver extends ResolverWithHistory
constructor
/**
* Construct a PackageResolver
*
* @param _uri - the URI to redirect to the wrap package
* @param wrapPackage - a wrap package
* */
constructor(private _uri: Uri, private wrapPackage: IWrapPackage)
Methods
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @returns text describing the URI resolution step
* */
protected getStepDescription = (): string
_tryResolveUri (protected)
/**
* Resolve a URI to a wrap package
*
* @param uri - the URI to resolve
* @returns A Promise with a Result containing a wrap package if successful
*/
protected async _tryResolveUri(
uri: Uri
): Promise<Result<UriPackageOrWrapper>>
RedirectResolver
/**
* A Uri Resolver that resolves to a new URI and correctly updates the
* resolution history.
* */
export class RedirectResolver<
TUri extends string | Uri = string
> extends ResolverWithHistory
constructor
/**
* Construct a RedirectResolver
*
* @param from - the URI to redirect from
* @param to - the URI to redirect to
* */
constructor(from: TUri, to: TUri)
Methods
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @returns text describing the URI resolution step
* */
protected getStepDescription = (): string
_tryResolveUri (protected)
/**
* Resolve a URI to a new URI
*
* @param uri - the URI to resolve
* @returns A Promise with a Result containing a URI if successful
*/
protected async _tryResolveUri(
uri: Uri
): Promise<Result<UriPackageOrWrapper>>
WrapperResolver
/**
* A Uri Resolver that resolves to an embedded wrapper and correctly updates
* the resolution history.
* */
export class WrapperResolver extends ResolverWithHistory
constructor
/**
* Construct a WrapperResolver
*
* @param _uri - the URI to redirect to the wrapper instance
* @param _wrapper - a wrapper
* */
constructor(private _uri: Uri, private _wrapper: Wrapper)
Methods
getStepDescription (protected)
/**
* A utility function for generating step descriptions to facilitate resolution context updates
*
* @returns text describing the URI resolution step
* */
protected getStepDescription = (): string
_tryResolveUri
/**
* Resolve a URI to a wrapper
*
* @param uri - the URI to resolve
* @returns A Promise with a Result containing a wrapper if successful
*/
protected async _tryResolveUri(
uri: Uri
): Promise<Result<UriPackageOrWrapper>>
StaticResolver
/**
* An IUriResolver implementation that efficiently delegates URI resolution to
* static resolvers--i.e. those that resolve to embedded URIs, Wrappers, and Packages
* */
export class StaticResolver<TError = undefined>
implements IUriResolver<TError>
constructor
/**
* Construct a Static Resolver
*
* @param uriMap - a mapping of URI to embedded URI, package, or wrapper
* */
constructor(public uriMap: Map<string, UriPackageOrWrapper>)
Methods
from
/**
* Create a StaticResolver from a static-resolver-like object
*
* @param staticResolverLikes - an array of resolver-like objects to delegate resolution to
*
* @returns a StaticResolver
* */
static from<TError = undefined>(
staticResolverLikes: UriResolverLike[]
): StaticResolver<TError>
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
*
* @param uri - the URI to resolve
* @param _ - not used
* @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
*/
async tryResolveUri(
uri: Uri,
_: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError>>
StaticResolverLike
/** A StaticResolverLike can be one of two things:
* - An object that can be transformed into a static IUriResolver
* - An array of StaticResolverLike
* */
export type StaticResolverLike =
| IUriRedirect
| IUriPackage
| IUriWrapper
| StaticResolverLike[];
RequestSynchronizerResolver
/* Uri resolver that synchronizes requests to the same URI
* Multiple requests to the same URI will be resolved only once
* and the result will be cached for subsequent requests (only for the duration of that first request)
* Can use the `shouldIgnoreCache` option to determine whether to ignore the cached request in case of an error
* (default is to use the cache)
*/
export class RequestSynchronizerResolver<TError>
implements IUriResolver<TError>
constructor
/**
* Construct a RequestSynchronizerResolver
*
* @param resolverToSynchronize - the inner resolve whose resolution will be synchronized
* @param options - the optional options containing the `shouldIgnoreCache` error handler
* */
constructor(
private resolverToSynchronize: IUriResolver<TError>,
private options?: {
shouldIgnoreCache?: (error: TError | undefined) => boolean;
}
)
Methods
from
/**
* Create a RequestSynchronizerResolver from a static-resolver-like object
*
* @param resolver - a resolver-like object whose resolution will be synchronized
* @param options - the optional options containing the `shouldIgnoreCache` error handler
*
* @returns a RequestSynchronizerResolver
* */
static from<TResolverError = unknown>(
resolver: UriResolverLike,
options?: {
shouldIgnoreCache?: (error: TResolverError | undefined) => boolean;
}
): RequestSynchronizerResolver<TResolverError>
tryResolveUri
/**
* Resolve a URI to a wrap package, a wrapper, or a URI.
* Attempts to resolve the URI using each of the aggregated resolvers sequentially.
*
* @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
*/
async tryResolveUri(
uri: Uri,
client: CoreClient,
resolutionContext: IUriResolutionContext
): Promise<Result<UriPackageOrWrapper, TError>>
Development
This package is open-source. It lives within the Polywrap JavaScript Client repository. Contributions from the community are welcomed!
Build
nvm use && yarn install && yarn build
Test
yarn test
``