Example #1
0
/**
 * 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();
}
Example #3
0
/**
 * 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);
  });
}
Example #5
0
/**
 * 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;
  });
}