"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mutate = void 0; /** ____ *--------------/ \.------------------/ * / swrv \. / // * / / /\. / // * / _____/ / \. / * / / ____/ . \. / * / \ \_____ \. / * / . \_____ \ \ / // * \ _____/ / ./ / // * \ / _____/ ./ / * \ / / . ./ / * \ / / ./ / * . \/ ./ / // * \ ./ / // * \.. / / * . ||| / * ||| / * . ||| / // * ||| / // * ||| / */ var vue_1 = require("vue"); var web_preset_1 = __importDefault(require("./lib/web-preset")); var cache_1 = __importDefault(require("./cache")); var DATA_CACHE = new cache_1.default(); var REF_CACHE = new cache_1.default(); var PROMISES_CACHE = new cache_1.default(); var defaultConfig = { cache: DATA_CACHE, refreshInterval: 0, ttl: 0, serverTTL: 1000, dedupingInterval: 2000, revalidateOnFocus: true, revalidateDebounce: 0, shouldRetryOnError: true, errorRetryInterval: 5000, errorRetryCount: 5, fetcher: web_preset_1.default.fetcher, isOnline: web_preset_1.default.isOnline, isDocumentVisible: web_preset_1.default.isDocumentVisible }; /** * Cache the refs for later revalidation */ function setRefCache(key, theRef, ttl) { var refCacheItem = REF_CACHE.get(key); if (refCacheItem) { refCacheItem.data.push(theRef); } else { // #51 ensures ref cache does not evict too soon var gracePeriod = 5000; REF_CACHE.set(key, [theRef], ttl > 0 ? ttl + gracePeriod : ttl); } } function onErrorRetry(revalidate, errorRetryCount, config) { if (!config.isDocumentVisible()) { return; } if (config.errorRetryCount !== undefined && errorRetryCount > config.errorRetryCount) { return; } var count = Math.min(errorRetryCount || 0, config.errorRetryCount); var timeout = count * config.errorRetryInterval; setTimeout(function () { revalidate(null, { errorRetryCount: count + 1, shouldRetryOnError: true }); }, timeout); } /** * Main mutation function for receiving data from promises to change state and * set data cache */ var mutate = function (key, res, cache, ttl) { if (cache === void 0) { cache = DATA_CACHE; } if (ttl === void 0) { ttl = defaultConfig.ttl; } return __awaiter(void 0, void 0, void 0, function () { var data, error, isValidating, err_1, newData, stateRef, refs_1; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!isPromise(res)) return [3 /*break*/, 5]; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, res]; case 2: data = _a.sent(); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); error = err_1; return [3 /*break*/, 4]; case 4: return [3 /*break*/, 6]; case 5: data = res; _a.label = 6; case 6: // eslint-disable-next-line prefer-const isValidating = false; newData = { data: data, error: error, isValidating: isValidating }; if (typeof data !== 'undefined') { try { cache.set(key, newData, ttl); } catch (err) { console.error('swrv(mutate): failed to set cache', err); } } stateRef = REF_CACHE.get(key); if (stateRef && stateRef.data.length) { refs_1 = stateRef.data.filter(function (r) { return r.key === key; }); refs_1.forEach(function (r, idx) { if (typeof newData.data !== 'undefined') { r.data = newData.data; } r.error = newData.error; r.isValidating = newData.isValidating; r.isLoading = newData.isValidating; var isLast = idx === refs_1.length - 1; if (!isLast) { // Clean up refs that belonged to old keys delete refs_1[idx]; } }); refs_1 = refs_1.filter(Boolean); } return [2 /*return*/, newData]; } }); }); }; exports.mutate = mutate; function useSWRV() { var _this = this; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var key; var fn; var config = __assign({}, defaultConfig); var unmounted = false; var isHydrated = false; var instance = (0, vue_1.getCurrentInstance)(); var vm = (instance === null || instance === void 0 ? void 0 : instance.proxy) || instance; // https://github.com/vuejs/composition-api/pull/520 if (!vm) { console.error('Could not get current instance, check to make sure that `useSwrv` is declared in the top level of the setup function.'); return null; } var IS_SERVER = (vm === null || vm === void 0 ? void 0 : vm.$isServer) || false; // #region ssr /** const isSsrHydration = Boolean( \!IS_SERVER && vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.swrvKey) */ // #endregion if (args.length >= 1) { key = args[0]; } if (args.length >= 2) { fn = args[1]; } if (args.length > 2) { config = __assign(__assign({}, config), args[2]); } var ttl = IS_SERVER ? config.serverTTL : config.ttl; var keyRef = typeof key === 'function' ? key : (0, vue_1.ref)(key); if (typeof fn === 'undefined') { // use the global fetcher fn = config.fetcher; } var stateRef = null; // #region ssr // if (isSsrHydration) { // // component was ssrHydrated, so make the ssr reactive as the initial data // const swrvState = (window as any).__SWRV_STATE__ || // ((window as any).__NUXT__ && (window as any).__NUXT__.swrv) || [] // const swrvKey = +(vm as any).$vnode.elm.dataset.swrvKey // if (swrvKey !== undefined && swrvKey !== null) { // const nodeState = swrvState[swrvKey] || [] // const instanceState = nodeState[isRef(keyRef) ? keyRef.value : keyRef()] // if (instanceState) { // stateRef = reactive(instanceState) // isHydrated = true // } // } // } // #endregion if (!stateRef) { stateRef = (0, vue_1.reactive)({ data: undefined, error: undefined, isValidating: true, isLoading: true, key: null }); } /** * Revalidate the cache, mutate data */ var revalidate = function (data, opts) { return __awaiter(_this, void 0, void 0, function () { var isFirstFetch, keyVal, cacheItem, newData, fetcher, shouldRevalidate, trigger; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: isFirstFetch = stateRef.data === undefined; keyVal = keyRef.value; if (!keyVal) { return [2 /*return*/]; } cacheItem = config.cache.get(keyVal); newData = cacheItem && cacheItem.data; stateRef.isValidating = true; stateRef.isLoading = !newData; if (newData) { stateRef.data = newData.data; stateRef.error = newData.error; } fetcher = data || fn; if (!fetcher || (!config.isDocumentVisible() && !isFirstFetch) || ((opts === null || opts === void 0 ? void 0 : opts.forceRevalidate) !== undefined && !(opts === null || opts === void 0 ? void 0 : opts.forceRevalidate))) { stateRef.isValidating = false; stateRef.isLoading = false; return [2 /*return*/]; } // Dedupe items that were created in the last interval #76 if (cacheItem) { shouldRevalidate = Boolean(((Date.now() - cacheItem.createdAt) >= config.dedupingInterval) || (opts === null || opts === void 0 ? void 0 : opts.forceRevalidate)); if (!shouldRevalidate) { stateRef.isValidating = false; stateRef.isLoading = false; return [2 /*return*/]; } } trigger = function () { return __awaiter(_this, void 0, void 0, function () { var promiseFromCache, fetcherArgs, newPromise, shouldRetryOnError; return __generator(this, function (_a) { switch (_a.label) { case 0: promiseFromCache = PROMISES_CACHE.get(keyVal); if (!!promiseFromCache) return [3 /*break*/, 2]; fetcherArgs = Array.isArray(keyVal) ? keyVal : [keyVal]; newPromise = fetcher.apply(void 0, __spreadArray([], __read(fetcherArgs), false)); PROMISES_CACHE.set(keyVal, newPromise, config.dedupingInterval); return [4 /*yield*/, mutate(keyVal, newPromise, config.cache, ttl)]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, mutate(keyVal, promiseFromCache.data, config.cache, ttl)]; case 3: _a.sent(); _a.label = 4; case 4: stateRef.isValidating = false; stateRef.isLoading = false; PROMISES_CACHE.delete(keyVal); if (stateRef.error !== undefined) { shouldRetryOnError = !unmounted && config.shouldRetryOnError && (opts ? opts.shouldRetryOnError : true); if (shouldRetryOnError) { onErrorRetry(revalidate, opts ? opts.errorRetryCount : 1, config); } } return [2 /*return*/]; } }); }); }; if (!(newData && config.revalidateDebounce)) return [3 /*break*/, 1]; setTimeout(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!!unmounted) return [3 /*break*/, 2]; return [4 /*yield*/, trigger()]; case 1: _a.sent(); _a.label = 2; case 2: return [2 /*return*/]; } }); }); }, config.revalidateDebounce); return [3 /*break*/, 3]; case 1: return [4 /*yield*/, trigger()]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/]; } }); }); }; var revalidateCall = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, revalidate(null, { shouldRetryOnError: false })]; }); }); }; var timer = null; /** * Setup polling */ (0, vue_1.onMounted)(function () { var tick = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(!stateRef.error && config.isOnline())) return [3 /*break*/, 2]; // if API request errored, we stop polling in this round // and let the error retry function handle it return [4 /*yield*/, revalidate()]; case 1: // if API request errored, we stop polling in this round // and let the error retry function handle it _a.sent(); return [3 /*break*/, 3]; case 2: if (timer) { clearTimeout(timer); } _a.label = 3; case 3: if (config.refreshInterval && !unmounted) { timer = setTimeout(tick, config.refreshInterval); } return [2 /*return*/]; } }); }); }; if (config.refreshInterval) { timer = setTimeout(tick, config.refreshInterval); } if (config.revalidateOnFocus) { document.addEventListener('visibilitychange', revalidateCall, false); window.addEventListener('focus', revalidateCall, false); } }); /** * Teardown */ (0, vue_1.onUnmounted)(function () { unmounted = true; if (timer) { clearTimeout(timer); } if (config.revalidateOnFocus) { document.removeEventListener('visibilitychange', revalidateCall, false); window.removeEventListener('focus', revalidateCall, false); } var refCacheItem = REF_CACHE.get(keyRef.value); if (refCacheItem) { refCacheItem.data = refCacheItem.data.filter(function (ref) { return ref !== stateRef; }); } }); // #region ssr // if (IS_SERVER) { // // make sure srwv exists in ssrContext // let swrvRes = [] // if (vm.$ssrContext) { // swrvRes = vm.$ssrContext.swrv = vm.$ssrContext.swrv || swrvRes // } // const ssrKey = swrvRes.length // if (!vm.$vnode || (vm.$node && !vm.$node.data)) { // vm.$vnode = { // data: { attrs: { 'data-swrv-key': ssrKey } } // } // } // const attrs = (vm.$vnode.data.attrs = vm.$vnode.data.attrs || {}) // attrs['data-swrv-key'] = ssrKey // // Nuxt compatibility // if (vm.$ssrContext && vm.$ssrContext.nuxt) { // vm.$ssrContext.nuxt.swrv = swrvRes // } // onServerPrefetch(async () => { // await revalidate() // if (!swrvRes[ssrKey]) swrvRes[ssrKey] = {} // swrvRes[ssrKey][keyRef.value] = { // data: stateRef.data, // error: stateRef.error, // isValidating: stateRef.isValidating // } // }) // } // #endregion /** * Revalidate when key dependencies change */ try { (0, vue_1.watch)(keyRef, function (val) { if (!(0, vue_1.isReadonly)(keyRef)) { keyRef.value = val; } stateRef.key = val; stateRef.isValidating = Boolean(val); setRefCache(keyRef.value, stateRef, ttl); if (!IS_SERVER && !isHydrated && keyRef.value) { revalidate(); } isHydrated = false; }, { immediate: true }); } catch (_a) { // do nothing } var res = __assign(__assign({}, (0, vue_1.toRefs)(stateRef)), { mutate: function (data, opts) { return revalidate(data, __assign(__assign({}, opts), { forceRevalidate: true })); } }); return res; } function isPromise(p) { return p !== null && typeof p === 'object' && typeof p.then === 'function'; } exports.default = useSWRV; //# sourceMappingURL=use-swrv.js.map