Source: api/middleware/cpb.js

import callerId from 'caller-id';
import { ShopIdService } from 'cpb-api';
import GetFiles from 'cpb-api/filestore/get.js';
import { get as GetShop } from 'cpb-api/middleware/shop.js';
import { getBinaryFlagValue, stringifyJSON, title } from 'cpb-common';
import Shopify from 'cpb-shopify';
import Webhooks from 'cpb-shopify/webhook/index.js';
import { File } from 'cpb-storage';

/**
 * ### Get all shop instance data
 * @param {!string|number} shopNameOrShopID
 * @param {?string|number} productIdOrHandle
 * @param {?number} generation
 * @param {?object} exclusions
 * @returns {Promise<{products}>}
 */
export async function get(shop, productIdOrHandle, generation, exclusions = {}) {
  //  if (!shopNameOrShopID) throw new TypeError('!shopNameOrShopID');

  const fetch = exclusions.fetch,
    promises = [],
    { id: shopID, name: shopName } = shop, //await ShopIdService.getIdName(shopNameOrShopID, fetch),
    cachedFile = `${shopID}/cpb.json`,
    onGetShopError = function onGetShopError(error, msg = 'middleware') {
      console.error(`[api/middleware/cpb.get][${shopID},${shopName}] Error: ${msg}`, error, callerId.getDetailedString());
      return { error };
    };

  let result;
  if (!fetch) {
    try {
      result = await File.read({ name: cachedFile, generation, json: true });
    } catch (error) {
      title(`[cpb-api/middleware/get][${shopID},${shopName}] ERROR.CachedFileNotFound`, error, callerId.getDetailedString());
    }
  }

  let needDatastoreSave;
  if (fetch || !result) {
    needDatastoreSave = true;
    result = result || { shopName, shopID };
    // requesting all the data at once
    promises.push(
      GetShop({ shopName }, fetch)
        .then(shop => (result.shop = shop))
        .catch(onGetShopError),

      GetFiles({ id: shopID, fetch, files: 1, versions: 1 })
        .then(async files => {
          files.productIds = Object.keys(files.productConfigs).map(a => +a);
          // listing product id;s existing on storage buckets
          if (files.productIds && files.productIds.length) {
            try {
              const [products, error] = await Shopify.Product.list({ shopName, ids: files.productIds }).catch(onGetShopError);
              if (error) throw error;
              result.products = products;
            } catch (error) {
              error.originator = 'Shopify.Product.list';
              console.error({ error }, callerId.getDetailedString());
              result.products = [];
              result.errors = result.errors || [];
              delete error.timings;
              result.errors.push(error);
            }

            for (const product of result.products) product.config = files.productConfigs[product.id];
          }

          // this contains the configs that need to be deleted since the Shopify Product is gone.
          const toRemove = [];
          for (const fileId of files.productIds) if (!result.products.find(product => product.id == fileId)) toRemove.push(files.productConfigs[fileId]);
          result.storage = { files, toRemove };
          //            for (const { path } of toRemove) File.delete({ path }).catch(console.error);
        })
        .catch(onGetShopError),

      Shopify.Charge.getActiveCharge(shopName || shopID, fetch)
        .then(charge => (result.charge = charge))
        .catch(onGetShopError),

      Webhooks.list(shopName, fetch)
        .then(([webhooks, error]) => {
          if (error) throw error;
          result.webhooks = webhooks;
        })
        .catch(onGetShopError),
    );
    try {
      await Promise.all(promises).catch(onGetShopError);
    } catch (error) {
      onGetShopError(error, 'GetShop', { ...arguments });
    }
  }

  for (const product of result.products || []) {
    const currentVersion = product.config.versions.find(v => v.isCurrent) || product.config.versions.pop();
    product.config = { ...product.config, ...currentVersion };

    // restoring accidentally deleted configs
    if (product.config.isDeleted) {
      console.warn('[cpb-api/middleware/cpb] FOUND_DELETED_CONFIG', product.config);
      await File.restore({ path: `${shopID}/${product.id}.json`, generation: currentVersion.generation }).catch(console.error);
    }
  }

  if (fetch || needDatastoreSave)
    File.upload({
      name: cachedFile,
      data: result,
    }).catch(console.error);

  for (const [key, val] of Object.entries(exclusions)) if (!val) delete result[key];

  if (productIdOrHandle) {
    result.product = result.products.find(p => p.id == productIdOrHandle || p.handle === productIdOrHandle);
    const configPath = result.product.config.path;

    if (generation) {
      const version = result.product.config.versions.find(value => value.generation === generation);
      console.debug({ generation, configPath, version });
      if (version) result.product.config = { ...result.product.config, ...version };
    }
    delete result.products;
    result.productData = await File.read({ name: configPath, generation }).catch(console.error);
  }

  return result;
}

/**
 *  ### [/cpb:${shopNameOrShopID] middleware
 * @param {Request} req
 * @param {Response} res
 */
export async function CPBWare(req, res) {
  if (!res.locals.shop) {
    console.error(`[CPBWare] NO_RES_LOCALS_SHOP`, res.locals, req.params);
    //    throw new TypeError('!res.locals.shop');
  }
  const fetch = getBinaryFlagValue(req.query.fetch, 0),
    generation = req.params.generation,
    exclusions = {
      fetch,
      storage: getBinaryFlagValue(req.query.files, 0),
      versions: getBinaryFlagValue(req.query.versions, 1),
      charges: getBinaryFlagValue(req.query.charges, 0),
      shop: getBinaryFlagValue(req.query.shop, 1),
      products: getBinaryFlagValue(req.query.products, 1),
      webhooks: getBinaryFlagValue(req.query.webhooks, 1),
    },
    //    shopIdOrName = res.locals.shopIdOrName || req.params.shopIdOrName,
    //    { id: shopID, name: shopName } = res.locals.shop || (await ShopIdService.getIdName(shopIdOrName)),
    productIdOrHandle = req.params.productIdOrHandle,
    debug = {
      //      shopID,
      //      shopName,
      //      shopIdOrName,
      productIdOrHandle,
      generation,
      exclusions,
      request: {
        rid: res.locals.rid,
        query: req.query,
        params: req.params,
        locals: res.locals,
      },
      timestamp: new Date(),
    };
  //  console.info(`[api/middleware/cpb]`, );
  try {
    const data = await get(res.locals.shop, productIdOrHandle, generation, exclusions);
    res
      .type('json')
      .status(200)
      .end(stringifyJSON({ ...data, debug }));
  } catch (error) {
    res.type('json').status(500).end(stringifyJSON({ error, debug }));
  }
}

export default CPBWare;