@lucidclient/speculate
Version:
A lightweight library to handle speculate rules for prefetching and prerendering documents, with added support for data fetching on intent.
171 lines (161 loc) • 4.42 kB
text/typescript
/**
* Initialises the speculation library using requestIdleCallback if available
*/
declare const init: () => () => void;
// --------------------------------------------------------
// Speculator
type IntentError<D> = {
message: string;
exception?: unknown;
details?: D;
};
type IntentResult<T, D> =
| { error: IntentError<D>; data: undefined }
| { error: undefined; data: NonNullable<T> };
type IntentResponse<T, D> = Promise<IntentResult<T, D>>;
type TargetElements =
| Element
| NodeListOf<Element>
| Element[]
| null
| undefined;
type OptimisticPrefetchStrategy = {
/**
* Elements to prefetch immediately when the strategy is active
*/
elements: TargetElements;
/**
* Priority order for prefetching (lower numbers = higher priority)
*/
priority?: number;
/**
* A condition that must be true for this strategy to be active
*/
condition?: () => boolean;
};
type SpeculatorConfig<T, D> = {
/**
* Elements that will trigger prefetching when user intent is determined
*/
elements: TargetElements;
/**
* Strategies for optimistically prefetching on initialisation when idle
*/
optimistic?: OptimisticPrefetchStrategy | OptimisticPrefetchStrategy[];
/**
* Callback that fetches the data for an element when user intent is determined
* @returns Promise that resolves with either data or an error
*/
fetch: (element: Element) => IntentResponse<T, D>;
/**
* Called when a target element is clicked
*/
onClick?: (e: Event, result: IntentResult<T, D>) => void;
/**
* Cache configuration to control data freshness and memory usage
*/
cache?: {
/**
* Maximum number of responses to keep in cache
* @default 5
*/
maxSize?: number;
/**
* How long cached responses remain valid (in milliseconds)
* @default 120000
*/
staleTime?: number;
};
/**
* Generate a cache key for an element. Used to store and retrieve cached responses.
* By default, it will fallback to the elements ID if it has one, otherwise responses will not be cached.
* Return null/undefined to skip caching for an element.
*/
getCacheKey?: (element: Element) => string | undefined | null;
/**
* Delay before prefetching on hover (in milliseconds).
* Helps avoid unnecessary loads during quick mouse movements.
* @default 200
*/
hoverDelay?: number;
};
declare class Speculator<T, D> {
private config;
private cache;
private abortController;
private intentDebounce;
constructor(config: SpeculatorConfig<T, D>);
/**
* Registers all required events
*/
private registerEvents;
/**
* The target mouseover event handler
*/
private mouseOverEventHandler;
/**
* The target click event handler
*/
private clickEventHandler;
/**
* Gets a cache key for an element
*/
private getCacheKey;
/**
* Checks if a cached item is stale
*/
private isStale;
/**
* Manages the cache size by removing oldest entries when limit is reached
*/
private manageCacheSize;
/**
* Handles optimistic prefetching based on configured strategies
*/
private handleOptimisticPrefetch;
/**
* Wraps the fetch callback to ensure consistent error handling
*/
private executeFetchCallback;
/**
* Scheduels the prefetch for when idle
*/
private schedulePrefetch;
/**
* Normalises a TargetElements value
*/
private normaliseTargets;
/**
* Cache config w/ defaults
*/
private get cacheConfig();
/**
* Normalises optimistic strategies
*/
private get optimisticStrategies();
/**
* Hover delay w/ config
*/
private get hoverDelay();
/**
* Destroys and resets the Speculator instance
*/
destroy(): void;
/**
* Refreshes the Speculator instance
*/
refresh(refreshConfig?: Partial<Pick<SpeculatorConfig<T, D>, "elements" | "optimistic">>): void;
/**
* Prefetch fetch callback for a given element.
*/
prefetch(element: Element): Promise<IntentResult<T, D>>;
/**
* Prefetch multiple elements at once
*/
prefetchAll(elements: Element[] | NodeListOf<Element>): Promise<IntentResult<T, D>[]>;
/**
* Clears a cache entry. If no element is provided, clears entire cache
*/
clearCache(element?: Element): void;
}
export { Speculator, init as speculateLinks };