UNPKG

@pinia/colada-plugin-retry

Version:
137 lines (136 loc) 5.05 kB
import { shallowRef, toValue } from "vue"; //#region src/retry.ts const RETRY_OPTIONS_DEFAULTS = { delay: (attempt) => { const time = Math.min(2 ** attempt * 1e3, 3e4); if (process.env.NODE_ENV === "development") console.debug(`⏲️ delaying attempt #${attempt + 1} by ${time}ms`); return time; }, retry: (count) => { if (process.env.NODE_ENV === "development") console.debug(`🔄 Retrying ${"🟨".repeat(count + 1)}${"⬜️".repeat(2 - count)}`); return count < 2; } }; /** * Plugin that adds the ability to retry failed queries. * * @param globalOptions - global options for the retries */ function PiniaColadaRetry(globalOptions) { const defaults = { ...RETRY_OPTIONS_DEFAULTS, ...globalOptions }; return ({ queryCache, scope }) => { const retryMap = /* @__PURE__ */ new Map(); let isInternalCall = false; queryCache.$onAction(({ name, args, after, onError }) => { if (name === "extend") { const [entry] = args; scope.run(() => { entry.ext.isRetrying = shallowRef(false); entry.ext.retryCount = shallowRef(0); entry.ext.retryError = shallowRef(null); }); if (process.env.NODE_ENV === "development") updateDevtoolsState(entry); return; } else if (name === "remove" || name === "cancel") { const [cacheEntry] = args; const key = cacheEntry.keyHash; const entry = retryMap.get(key); if (entry) { clearTimeout(entry.timeoutId); retryMap.delete(key); } cacheEntry.ext.isRetrying.value = false; cacheEntry.ext.retryCount.value = 0; cacheEntry.ext.retryError.value = null; if (process.env.NODE_ENV === "development") updateDevtoolsState(cacheEntry); } else if (name === "fetch") { const [queryEntry] = args; const localOptions = queryEntry.options?.retry; const options = { ...typeof localOptions === "object" ? localOptions : { retry: localOptions } }; const retry = options.retry ?? defaults.retry; const delay = options.delay ?? defaults.delay; if (retry === 0) return; const key = queryEntry.keyHash; clearTimeout(retryMap.get(key)?.timeoutId); if (!isInternalCall) { retryMap.delete(key); queryEntry.ext.isRetrying.value = false; queryEntry.ext.retryCount.value = 0; queryEntry.ext.retryError.value = null; if (process.env.NODE_ENV === "development") updateDevtoolsState(queryEntry); } const previousState = queryEntry.state.value; const retryFetch = () => { if (queryEntry.state.value.status === "error") { const error = queryEntry.state.value.error; let entry = retryMap.get(key); if (!entry) { entry = { retryCount: 0 }; retryMap.set(key, entry); } if (typeof retry === "number" ? retry > entry.retryCount : retry(entry.retryCount, error)) { queryEntry.ext.isRetrying.value = true; queryEntry.ext.retryCount.value = entry.retryCount + 1; queryEntry.ext.retryError.value = error; if (process.env.NODE_ENV === "development") updateDevtoolsState(queryEntry); queryEntry.state.value = previousState; const delayTime = typeof delay === "function" ? delay(entry.retryCount) : delay; queryEntry.when = 0; entry.timeoutId = setTimeout(() => { if (!queryEntry.active || toValue(queryEntry.options?.enabled) === false) { retryMap.delete(key); queryEntry.ext.isRetrying.value = false; queryEntry.ext.retryCount.value = 0; queryEntry.ext.retryError.value = null; if (process.env.NODE_ENV === "development") updateDevtoolsState(queryEntry); return; } isInternalCall = true; Promise.resolve(queryCache.fetch(queryEntry)).catch(process.env.NODE_ENV !== "test" ? console.error : () => {}); isInternalCall = false; if (entry) entry.retryCount++; }, delayTime); } else { queryEntry.ext.isRetrying.value = false; queryEntry.ext.retryError.value = null; retryMap.delete(key); if (process.env.NODE_ENV === "development") updateDevtoolsState(queryEntry); } } else { queryEntry.ext.isRetrying.value = false; queryEntry.ext.retryCount.value = 0; queryEntry.ext.retryError.value = null; retryMap.delete(key); if (process.env.NODE_ENV === "development") updateDevtoolsState(queryEntry); } }; onError(retryFetch); after(retryFetch); } }); }; } /** * Updates the devtools state for the retry plugin. Only used in development mode. * * @param entry - the query entry to update * * @internal */ function updateDevtoolsState(entry) { if (entry.ext.retry) { entry.ext.retry.isRetrying = entry.ext.isRetrying.value; entry.ext.retry.retryCount = entry.ext.retryCount.value; entry.ext.retry.retryError = entry.ext.retryError.value; } else entry.ext.retry ??= { isRetrying: entry.ext.isRetrying.value, retryCount: entry.ext.retryCount.value, retryError: entry.ext.retryError.value }; } //#endregion export { PiniaColadaRetry }; //# sourceMappingURL=index.mjs.map