Source: api/filestore/list.js

import app, { cleanupData } from 'cpb-api';
import { title } from 'cpb-common';
import { File, getTopLevelDirs, getTopLevelFiles } from 'cpb-storage';
import { getShopifyStoreIdFromDir } from 'cpb-storage/shared.js';

/**
 * @typedef {Object} StoreList
 * @property {string} bucket - gce storage bucket
 * @property {number[]} ids - shopify filestore ids
 * @property {string[]} misc - misc dirs
 * @property {string[]} legacy - legacy shopify filestore domains
 * @property {string[]?} files - loose files
 * @property {string[]?} deletedFiles - deleted loose files
 * @property {BucketStorageStats} stats - storage stats
 */

/**
 * ### List all stores data in the given bucket.
 * If *fetch* flag is se - read file `index.json` if present. Otherwise generate new index file
 * @method module:cpb-api/filestore.list
 * @async
 * @param {string} [bucket=${process.env.BUCKET}] - gce bucket
 * @param {boolean} [fetch=false] - fetch new data if true or use existing
 *   index if present
 * @param {boolean} [versions=false] - include file versions
 * @param {boolean} [files=true] - include array with files to the output
 * @param {string} [indexFileName='index.json'] - index file name
 * @param {boolean} [legacy=true] - include array of the legacy shopify filestore dirs (ones with the name that
 * includes.myshopify in it )
 * @param {boolean} [misc=true] - include array of the uncategorized directories
 *   (ones that are neither shopifyStoreIds nor the shopify filestore domains)
 * @returns {StoreList}
 * @throws {Error} NO_DATA_FOUND
 */
export default async function list({
  bucket = app.get('bucket'),
  indexFileName = 'index.json',
  fetch = false,
  versions = false,
  files = true,
  misc = true,
  legacy = true,
} = {}) {
  title('StoreList', { ...arguments });

  /**
   * reads index file from the bucket and returns its contents
   * @async
   * @param {string} bucketName
   * @param {string} indexFileName
   * @returns {StoreList} data
   */
  async function readIndexFile(bucketName, indexFileName) {
    let data;
    try {
      data = await File.read({ bucket: bucketName, name: indexFileName }).catch(console.error);
    } catch (error) {
      console.error(`ERROR.StoreList.CACHED`, { bucketName, indexFileName, error });
    }
    return data;
  }

  /**
   * generates new bucket index file that contains grouped files and filestore ids
   * @async
   * @param {string} bucketName
   * @param {string} indexFileName
   * @returns {StoreList}
   */
  async function generateIndexFile(bucketName, indexFileName) {
    const [files, deletedFiles] = await getTopLevelFiles({ bucket: bucketName }),
      inventory = await getTopLevelDirs({ bucket: bucketName }),
      ids = [],
      misc = [],
      legacy = [];

    inventory.dirs.map(dir => {
      const shopifyStoreId = getShopifyStoreIdFromDir({ dir: dir.name });
      if (!shopifyStoreId) {
        if (dir.name.indexOf('myshopify') !== -1) {
          legacy.push(dir.name);
        } else misc.push(dir.name);
      } else ids.push(shopifyStoreId);
    });

    const data = {
      bucket: bucketName,
      ids,
      misc,
      legacy,
      files,
      deletedFiles,
      stats: {
        ids: ids.length,
        legacy: legacy.length,
        misc: misc.length,
        files: files.length,
        deletedFiles: deletedFiles.length,
      },
    };
    File.upload({ bucket: bucketName, name: indexFileName, data }).then(console.info).catch(console.error);

    return data;
  }

  let result;
  if (!fetch) {
    result = await readIndexFile(bucket, indexFileName);
    if (result) return cleanupData(result, { legacy, misc, files, versions });
  }
  result = await generateIndexFile(bucket, indexFileName); // .catch(console.error);
  if (result) return cleanupData(result, { legacy, misc, files, versions });

  // something went very wrong here...at least some data should be present in the bucket
  throw new Error('NO_DATA_FOUND');
}