static flattenRequests(tree) {
    /** @type {LH.Audit.Details.SimpleCriticalRequestNode} */
    const flattendChains = {};
    /** @type {Map<string, LH.Audit.Details.SimpleCriticalRequestNode[string]>} */
    const chainMap = new Map();

    /** @param {CrcNodeInfo} opts */
    function flatten(opts) {
      const request = opts.node.request;
      const simpleRequest = {
        url: request.url,
        startTime: request.networkRequestTime / 1000,
        endTime: request.networkEndTime / 1000,
        responseReceivedTime: request.responseHeadersEndTime / 1000,
        transferSize: request.transferSize,
      };

      let chain = chainMap.get(opts.id);
      if (chain) {
        chain.request = simpleRequest;
      } else {
        chain = {
          request: simpleRequest,
        };
        flattendChains[opts.id] = chain;
      }

      if (opts.node.children) {
        for (const chainId of Object.keys(opts.node.children)) {
          // Note: cast should be Partial<>, but filled in when child node is traversed.
          const childChain = /** @type {LH.Audit.Details.SimpleCriticalRequestNode[string]} */ ({
            request: {},
          });
          chainMap.set(chainId, childChain);
          if (!chain.children) {
            chain.children = {};
          }
          chain.children[chainId] = childChain;
        }
      }
      chainMap.set(opts.id, chain);
    }

    CriticalRequestChains._traverse(tree, flatten);

    return flattendChains;
  }
@param {LH.Artifacts.CriticalRequestNode} tree
@return {LH.Audit.Details.SimpleCriticalRequestNode}