function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps, resultFiles }) {
  /**
   * @param {string} projectPath
   * @returns {object|null}
   */
  function getPackageJson(projectPath) {
    try {
      const file = path.resolve(projectPath, 'package.json');
      return JSON.parse(fsAdapter.fs.readFileSync(file, 'utf8'));
    } catch (_) {
      return null;
    }
  }

  /**
   * @param {object[]} collections
   * @returns {{[key as string]: }}
   */
  function transformToProjectNames(collections) {
    const res = {};
    // eslint-disable-next-line array-callback-return
    Object.entries(collections).map(([key, val]) => {
      res[key] = val.map(c => {
        const pkg = getPackageJson(c);
        return pkg?.name;
      });
    });
    return res;
  }

  const pathFromServerRootToHere = `/${path.relative(
    process.cwd(),
    getCurrentDir(import.meta.url),
  )}`;

  return [
    // eslint-disable-next-line consistent-return
    async (ctx, next) => {
      // TODO: Quick and dirty solution: refactor in a nicer way
      if (ctx.url.startsWith('/app')) {
        ctx.url = `${pathFromServerRootToHere}/${ctx.url}`;
        return next();
      }
      if (ctx.url === '/') {
        ctx.url = `${pathFromServerRootToHere}/index.html`;
        return next();
      }
      if (ctx.url === '/results.json') {
        ctx.type = 'application/json';
        ctx.body = resultFiles;
      } else if (ctx.url === '/menu-data.json') {
        // Gathers all data that are relevant to create a configuration menu
        // at the top of the dashboard:
        // - referenceCollections as defined in providence.conf.js
        // - searchTargetCollections (aka programs) as defined in providence.conf.js
        // - searchTargetDeps as found in search-target-deps-file.json
        // Also do some processing on the presentation of a project, so that it can be easily
        // outputted in frontend
        let searchTargetCollections;
        if (providenceConf.searchTargetCollections) {
          searchTargetCollections = transformToProjectNames(providenceConf.searchTargetCollections);
        } else {
          searchTargetCollections = Object.keys(searchTargetDeps).map(d => d.split('#')[0]);
        }

        const menuData = {
          // N.B. theoretically there can be a mismatch between basename and pkgJson.name,
          // but we assume folder names and pkgJson.names to be similar
          searchTargetCollections,
          referenceCollections: transformToProjectNames(providenceConf.referenceCollections),
          searchTargetDeps,
        };

        ctx.type = 'application/json';
        ctx.body = menuData;
      } else if (ctx.url === '/providence-conf.js') {
        // Allows frontend dasbboard app to find categories and other configs
        ctx.type = 'application/javascript';
        ctx.body = providenceConfRaw;
      } else {
        await next();
      }
    },
  ];
}
@param {{ providenceConf: object; providenceConfRaw:string; searchTargetDeps: object; resultFiles: string[]; }}