/** * Remove all non-SSR main nav routes from cache and state. * * @returns {Promise} resolves to array of booleans representing cache deletions. */ function removeAndInvalidateNonSSRRoutes () { return idb.get(idb.stores.init, 'routes').then((routes = {}) => { const nonSSRRouteUrls = Object.keys(routes).filter((url) => { return !routes[url].ssr; }); // Invalidate (will not skip fetchAndCache) nonSSRRouteUrls.forEach((url) => { routes[url].timestamp = 0; }); if (nonSSRRouteUrls.length > 0) { return idb.put(idb.stores.init, 'routes', routes) .then(() => { return caches.open(toolbox.options.cache.name); }) .then((cache) => { return Promise.all( nonSSRRouteUrls.map((url) => { return cache.delete(new Request(url), { ignoreSearch: true, ignoreMethod: true, ignoreVary: true }); }) ); }); } return Promise.resolve([]); }); }
export function resourceContentResponse (request) { const matches = request.match(/resource=([\w\-]+)/), resource = matches && matches[1]; if (resource) { return idb.get(idb.stores.init, keyName).then((payload) => { const content = payload && payload.ContentStore && payload.ContentStore.contents[resource]; debug( 'resourceContentResponse, resource:', resource, ', response:', content ); return new Promise((resolve, reject) => { if (content) { const blob = new Blob([JSON.stringify( apiHelpers.createContentResponse(content) )], { type: 'application/json' }); resolve(new Response(blob)); } else { reject(new Error(`Content not found for resource: ${resource}`)); } }); }); } // No resource, so Promise resolves to undefined. debug('resourceContentResponse: no resource'); return Promise.resolve(); }
/** * Add the given successful request url and timestamp to init.routes IDB store. * This is a fetchAndCache successHandler that stores the request times * as a side effect and just returns the response. * * @private * * @param {Boolean} serverSideRender - [0 or 1] 1 means serverSideRender. * @param {Request} request - The request of the successful network fetch. * @param {Response} response - The response of the successful network fetch. * @returns {Promise} A Promise resolving to the input response. */ function addRecentRoute (serverSideRender, request, response) { return idb.get(idb.stores.init, 'routes').then((routes = {}) => { const url = (new URL(request.url, location.origin)).pathname; routes[url] = routes[url] || {}; routes[url].timestamp = Date.now(); routes[url].ssr = serverSideRender === 1; return idb.put(idb.stores.init, 'routes', routes).then(() => { return response; }); }); }
/** * Keep old ContentStore content if it does not exist in newStores. * This is used by resourceContentResponse * @see resourceContentResponse * * NOTE: This grows the content over time. There is not currently a purging * mechanism. * TODO: Add IndexedDB purge to activate. * * @param {Object} newStores - The newer version of Flux Store data. * @param {Object} newStores.ContentStore.contents - The new contents * (will be merged with old content) * @return {Promise} A Promise that resolves to the new data merged with old content. */ function mergeContent (newStores) { return idb.get(idb.stores.init, keyName).then((oldStores) => { if (newStores && oldStores) { const oldContent = oldStores.ContentStore.contents, newContent = newStores.ContentStore.contents; Object.keys(oldContent).forEach((resource) => { // If the content is missing in newStores, it lives on. if (!newContent[resource]) { newContent[resource] = oldContent[resource]; } }); } return Promise.resolve(newStores); }); }
/** * Look up the given url in 'init.routes' to see if fetchAndCache should be * skipped. If age is less than TTL and already cached, skip. * * @private * * @param {String} url - The url pathname to test. * @returns {Promise} Promise resolves to Boolean, true if cache should be skipped. */ function getRecentRoute (url) { return idb.get(idb.stores.init, 'routes').then((routes) => { if (routes && routes[url]) { const age = Date.now() - routes[url].timestamp; if (age < routeTTL) { return toolbox.cacheOnly(new Request(url)).then((response) => { if (response) { debug(`skipping fetchAndCache for ${url}`); return true; } return false; }); } } return false; }); }