/**
 * Caches all JS files built by Remix in a browser cache.
 * This will use the Remix manifest to determine which files to cache.
 * It will get every JS file, get all the already cached URLs, remove any
 * old file, and finally add the new files to the cache.
 *
 * **This can only be run inside entry.client**
 */
export async function cacheAssets({
  cacheName = "assets",
  buildPath = "/build/",
} = {}) {
  let paths = getFilePaths();
  let cache = await caches.open(cacheName);
  let urls = await getCachedUrls(cache, buildPath);
  await removeOldAssets(cache, paths, urls);
  await addNewAssets(cache, paths, urls);
}
function getFilePaths() {
  try {
    return unique([
      ...Object.values(window.__remixManifest.routes).flatMap((route) => {
        return [route.module, ...(route.imports ?? [])];
      }),
      window.__remixManifest.url,
      window.__remixManifest.entry.module,
      ...window.__remixManifest.entry.imports,
    ]);
  } catch {
    throw new Error("Failed to get file paths from Remix manifest");
  }
}
async function getCachedUrls(cache, buildPath = "/build/") {
  try {
    let keys = await cache.keys();
    return keys
      .map((key) => {
        return new URL(key.url);
      })
      .filter((url) => url.hostname === window.location.hostname)
      .map((url) => url.pathname)
      .filter((pathname) => pathname.startsWith(buildPath));
  } catch {
    throw new Error("Failed to retrieve cached URLs");
  }
}
async function removeOldAssets(cache, paths, urls) {
  try {
    await Promise.all(
      urls
        .filter((pathname) => !paths.includes(pathname))
        .map((pathname) => cache.delete(pathname))
    );
  } catch {
    throw new Error("Failed to remove old assets from the cache");
  }
}
async function addNewAssets(cache, paths, urls) {
  try {
    await cache.addAll(paths.filter((path) => !urls.includes(path)));
  } catch {
    throw new Error("Failed to add new assets to the cache");
  }
}
function unique(array) {
  return [...new Set(array)];
}
