UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

59 lines (58 loc) 2.41 kB
import { AVOID_REFRESH } from "../../store/FetchStore.js"; import { awaitValues } from "../../util/async.js"; import { awaitDispose } from "../../util/dispose.js"; import { setMapItem } from "../../util/map.js"; import { EndpointStore } from "../store/EndpointStore.js"; /** * Cache of `EndpointStore` objects for a single endpoint, keyed by serialized payload. * - Use `get(payload)` to retrieve or create the `EndpointStore` for a given payload. */ export class EndpointCache { _endpoints = new Map(); endpoint; provider; constructor(endpoint, provider) { this.endpoint = endpoint; this.provider = provider; } /** Get (or create) the `EndpointStore` for the given payload. */ get(payload, caller = this.get) { const url = this.provider.renderURL(this.endpoint, payload, caller).href; return this._endpoints.get(url) || setMapItem(this._endpoints, url, new EndpointStore(this.endpoint, payload, this.provider)); } /** * Fetch (or return a cached result) for the given payload. * - Returns the cached value immediately if one exists. * - Waits for the in-flight fetch if the store is loading. * - Throws if the fetch fails, matching `APIProvider.call` behaviour. * * @param maxAge The maximum age (defaults to only refreshing if the value is still in a loading state). */ async call(payload, maxAge = AVOID_REFRESH, caller = this.call) { const store = this.get(payload, caller); await store.refresh(maxAge); return store.value; } /** Invalidate a specific store. */ invalidate(payload, caller = this.invalidate) { this.get(payload, caller)?.invalidate(); } /** Invalidate all stores. */ invalidateAll() { for (const store of this._endpoints.values()) store.invalidate(); } /** Trigger a refetch on a specific store. */ async refresh(payload, maxAge, caller = this.invalidate) { await this.get(payload, caller)?.refresh(maxAge); } /** Trigger a refetch on all stores. */ async refreshAll(maxAge) { await awaitValues(...this._endpoints.values().map(store => store.refresh(maxAge))); } // Implement `AsyncDisposable` [Symbol.asyncDispose]() { return awaitDispose(...this._endpoints.values(), // Dispose all endpoints. () => this._endpoints.clear()); } }