UNPKG

swr-store

Version:
493 lines (482 loc) 14.3 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { createSWRStore: () => createSWRStore, mutate: () => mutate, subscribe: () => subscribe, trigger: () => trigger }); module.exports = __toCommonJS(src_exports); // src/global.ts var import_lite = require("dequal/lite"); // src/cache/reactive-cache.ts function createReactiveCache() { return { cache: /* @__PURE__ */ new Map(), subscribers: /* @__PURE__ */ new Map() }; } function createReactiveCacheRef(cache, key, value) { const currentRef = cache.cache.get(key); if (currentRef) { return currentRef; } const newRef = { value }; cache.cache.set(key, newRef); return newRef; } function subscribeReactiveCache(cache, key, listener) { let subscribers = cache.subscribers.get(key); if (!subscribers) { subscribers = /* @__PURE__ */ new Set(); cache.subscribers.set(key, subscribers); } subscribers.add(listener); return () => { if (subscribers) { subscribers.delete(listener); } }; } function setReactiveCacheValue(cache, key, value, notify = true) { const currentRef = createReactiveCacheRef(cache, key, value); currentRef.value = value; if (notify) { let subscribers = cache.subscribers.get(key); if (!subscribers) { subscribers = /* @__PURE__ */ new Set(); cache.subscribers.set(key, subscribers); } for (const listener of subscribers.keys()) { listener(value); } } } function getReactiveCacheListenerSize(cache, key) { const result = cache.subscribers.get(key); if (result) { return result.size; } return 0; } // src/cache/mutation-cache.ts var MUTATION_CACHE = createReactiveCache(); function subscribeMutation(key, listener) { return subscribeReactiveCache(MUTATION_CACHE, key, listener); } function setMutation(key, value) { setReactiveCacheValue(MUTATION_CACHE, key, value); } function getMutation(key) { const result = MUTATION_CACHE.cache.get(key); if (result) { return result.value; } return void 0; } function getMutationListenerSize(key) { return getReactiveCacheListenerSize(MUTATION_CACHE, key); } // src/cache/revalidation-cache.ts var REVALIDATION_CACHE = createReactiveCache(); function subscribeRevalidation(key, listener) { return subscribeReactiveCache(REVALIDATION_CACHE, key, listener); } function setRevalidation(key, value, notify = true) { setReactiveCacheValue(REVALIDATION_CACHE, key, value, notify); } // src/global.ts function trigger(key, shouldRevalidate = true) { setRevalidation(key, shouldRevalidate); } function mutate(key, data, shouldRevalidate = true, compare = import_lite.dequal) { setRevalidation(key, shouldRevalidate); const current = getMutation(key); if (current && current.result.status === "success" && data.status === "success" && compare(current.result.data, data.data)) { current.timestamp = Date.now(); return; } setMutation(key, { result: data, timestamp: Date.now(), isValidating: false }); } function subscribe(key, listener) { const wrappedListener = (value) => { listener(value); }; return subscribeMutation(key, wrappedListener); } // src/default-config.ts var import_lite2 = require("dequal/lite"); function defaultKey(...args) { return JSON.stringify(args); } var DEFAULT_CONFIG = { revalidateOnFocus: false, revalidateOnNetwork: false, revalidateOnVisibility: false, refreshWhenHidden: false, refreshWhenBlurred: false, refreshWhenOffline: false, freshAge: 2e3, staleAge: 3e4, key: defaultKey, compare: import_lite2.dequal, maxRetryInterval: 5e3 }; var default_config_default = DEFAULT_CONFIG; // src/is-client.ts var IS_CLIENT = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; var is_client_default = IS_CLIENT; // src/retry.ts function createResolvable() { let resolve = () => { }; let reject = () => { }; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } function retry(supplier, options) { let alive = true; let schedule; const resolvable = createResolvable(); const backoff = (timeout = 10, count = 0) => { const handle = (reason) => { if (!alive || typeof options.count === "number" && options.count <= count) { resolvable.reject(reason); } else { schedule = window.setTimeout(() => { backoff(Math.max(10, Math.min(options.interval, timeout * 2)), count + 1); }, timeout); } }; try { supplier().then(resolvable.resolve, handle); } catch (reason) { handle(reason); } }; backoff(); return { resolvable, cancel: () => { if (schedule) { clearTimeout(schedule); } alive = false; } }; } // src/create-swr-store.ts var index = 0; function getIndex() { const current = index; index += 1; return current; } var retries = /* @__PURE__ */ new Map(); var { assign } = Object; function revalidate(fullOpts, args, opts) { const defaultRevalidateOptions = { shouldRevalidate: true, initialData: fullOpts.initialData, hydrate: false }; const revalidateOptions = assign( {}, defaultRevalidateOptions, opts ); const generatedKey = fullOpts.key(...args); const timestamp = Date.now(); let currentMutation = getMutation(generatedKey); if (!currentMutation && revalidateOptions.initialData) { currentMutation = { result: { data: revalidateOptions.initialData, status: "success" }, timestamp, isValidating: false }; if (revalidateOptions.hydrate) { setMutation(generatedKey, currentMutation); } } if (currentMutation) { if (!revalidateOptions.shouldRevalidate) { return currentMutation.result; } if (currentMutation.timestamp + fullOpts.freshAge > timestamp) { return currentMutation.result; } if (currentMutation.result.status === "pending") { const previousRetry = retries.get(generatedKey); if (previousRetry) { previousRetry.cancel(); } } } const pendingRetry = retry(() => fullOpts.get(...args), { count: fullOpts.maxRetryCount, interval: fullOpts.maxRetryInterval }); retries.set(generatedKey, pendingRetry); const pendingData = pendingRetry.resolvable.promise; const result = { data: pendingData, status: "pending" }; pendingData.then( (data) => { const mutation = getMutation(generatedKey); const shouldUpdate = () => { if (mutation == null) { return true; } if (mutation.timestamp > timestamp) { return false; } if (mutation.result.status === "success") { return !fullOpts.compare( mutation.result.data, data ); } return true; }; if (shouldUpdate()) { setMutation(generatedKey, { result: { data, status: "success" }, timestamp: mutation && mutation.timestamp ? mutation.timestamp : Date.now(), isValidating: false }); } }, (data) => { const mutation = getMutation(generatedKey); const shouldUpdate = () => { if (mutation == null) { return true; } if (mutation.timestamp > timestamp) { return false; } return true; }; if (shouldUpdate()) { setMutation(generatedKey, { result: { data, status: "failure" }, timestamp: mutation && mutation.timestamp ? mutation.timestamp : Date.now(), isValidating: false }); } } ); if (currentMutation && currentMutation.timestamp + fullOpts.freshAge + fullOpts.staleAge > timestamp) { currentMutation.timestamp = timestamp; currentMutation.isValidating = true; return currentMutation.result; } setMutation(generatedKey, { result, timestamp, isValidating: true }); return result; } function lazyRegister(cleanups, generatedKey, fullOpts, args) { if (getMutationListenerSize(generatedKey) > 0) { return; } const currentCleanups = []; const subscription = (sub) => { currentCleanups.push(sub()); }; const onRevalidate = () => { setRevalidation(generatedKey, true); }; subscription(() => { const innerRevalidate = (flag) => { revalidate(fullOpts, args, { shouldRevalidate: flag }); }; return subscribeRevalidation(generatedKey, innerRevalidate); }); if (is_client_default) { if (fullOpts.refreshInterval != null) { if (fullOpts.refreshWhenBlurred) { subscription(() => { let interval; const enter = () => { window.clearInterval(interval); interval = window.setInterval(onRevalidate, fullOpts.refreshInterval); }; const exit = () => { window.clearInterval(interval); interval = void 0; }; window.addEventListener("blur", enter, false); window.addEventListener("focus", exit, false); return () => { window.removeEventListener("blur", enter, false); window.removeEventListener("focus", exit, false); window.clearInterval(interval); }; }); } if (fullOpts.refreshWhenOffline) { subscription(() => { let interval; const enter = () => { window.clearInterval(interval); interval = window.setInterval(onRevalidate, fullOpts.refreshInterval); }; const exit = () => { window.clearInterval(interval); interval = void 0; }; window.addEventListener("offline", enter, false); window.addEventListener("online", exit, false); return () => { window.removeEventListener("offline", enter, false); window.removeEventListener("online", exit, false); window.clearInterval(interval); }; }); } if (fullOpts.refreshWhenHidden) { subscription(() => { let interval; const onVisibility = () => { window.clearInterval(interval); if (document.visibilityState === "visible") { interval = void 0; } else { interval = window.setInterval(onRevalidate, fullOpts.refreshInterval); } }; document.addEventListener("visibilitychange", onVisibility, false); return () => { document.removeEventListener("visibilitychange", onVisibility, false); window.clearInterval(interval); }; }); } if (!(fullOpts.refreshWhenHidden || fullOpts.refreshWhenBlurred || fullOpts.refreshWhenOffline)) { subscription(() => { const interval = window.setInterval(onRevalidate, fullOpts.refreshInterval); return () => { window.clearInterval(interval); }; }); } } if (fullOpts.revalidateOnFocus) { subscription(() => { window.addEventListener("focus", onRevalidate, false); return () => { window.removeEventListener("focus", onRevalidate, false); }; }); } if (fullOpts.revalidateOnNetwork) { subscription(() => { window.addEventListener("online", onRevalidate, false); return () => { window.removeEventListener("online", onRevalidate, false); }; }); } if (fullOpts.revalidateOnVisibility) { subscription(() => { const onVisible = () => { if (document.visibilityState === "visible") { onRevalidate(); } }; window.addEventListener("visibilitychange", onVisible, false); return () => { window.removeEventListener("visibilitychange", onVisible, false); }; }); } } cleanups.set(generatedKey, currentCleanups); } function lazyUnregister(cleanups, generatedKey) { if (getMutationListenerSize(generatedKey) === 0) { const actualCleanups = cleanups.get(generatedKey); if (actualCleanups) { for (let i = 0, len = actualCleanups.length; i < len; i += 1) { actualCleanups[i](); } cleanups.delete(generatedKey); } } } function createSWRStore(options) { const fullOpts = assign({}, default_config_default, options); const cleanups = /* @__PURE__ */ new Map(); return { id: `SWRStore-${getIndex()}`, trigger: (args, shouldRevalidate = true) => { const generatedKey = fullOpts.key(...args); trigger(generatedKey, shouldRevalidate); }, mutate: (args, data, shouldRevalidate = true, compare = fullOpts.compare) => { const generatedKey = fullOpts.key(...args); mutate(generatedKey, data, shouldRevalidate, compare); }, // This function revalidates the mutation cache // through reactive process get: (args, opts) => revalidate(fullOpts, args, opts), subscribe: (args, listener) => { const generatedKey = fullOpts.key(...args); lazyRegister(cleanups, generatedKey, fullOpts, args); const unsubscribe = subscribe(generatedKey, listener); return () => { unsubscribe(); lazyUnregister(cleanups, generatedKey); }; } }; } //# sourceMappingURL=index.cjs.map