```ts
/** A storage report over a tree of named folders and byte-sized files. */

function checkNode(node: any): void {
  if (typeof node !== "object" || node === null || Array.isArray(node)) {
    throw new Error("each node must be a mapping");
  }
  if (typeof node.name !== "string" || node.name.length === 0 || node.name.includes("/")) {
    throw new Error("each name must be a non-empty string without slashes");
  }
  if (("bytes" in node) === ("children" in node)) {
    throw new Error("a node holds either bytes or children");
  }
  if ("bytes" in node) {
    if (!Number.isInteger(node.bytes) || node.bytes < 0) {
      throw new Error("bytes must be a non-negative whole number");
    }
  } else if (!Array.isArray(node.children)) {
    throw new Error("children must be a list");
  }
}

function checkMinBytes(minBytes: number): void {
  if (!Number.isInteger(minBytes) || minBytes < 0) {
    throw new Error("minBytes must be a non-negative whole number");
  }
}

export function filePaths(root: object): string[] {
  const paths: string[] = [];
  const stack: [any, string][] = [[root, ""]];
  while (stack.length > 0) {
    const [node, prefix] = stack.pop()!;
    checkNode(node);
    const path = prefix + node.name;
    if ("bytes" in node) {
      paths.push(path);
    } else {
      for (let i = node.children.length - 1; i >= 0; i--) {
        stack.push([node.children[i], path + "/"]);
      }
    }
  }
  return paths;
}

export function treeBytes(root: object): number {
  let total = 0;
  const stack: any[] = [root];
  while (stack.length > 0) {
    const node = stack.pop();
    checkNode(node);
    if ("bytes" in node) {
      total += node.bytes;
    } else {
      for (const child of node.children) {
        stack.push(child);
      }
    }
  }
  return total;
}

export function heavyFolders(root: object, minBytes: number): [string, number][] {
  checkMinBytes(minBytes);
  const paths = filePaths(root);
  const folderMap = new Map<string, number>();
  for (const path of paths) {
    let currentPath = "";
    for (const part of path.split("/")) {
      if (part !== "") {
        currentPath += "/" + part;
        if (!folderMap.has(currentPath)) {
          folderMap.set(currentPath, treeBytes({ name: part, children: [] }));
        }
        const total = folderMap.get(currentPath)! + treeBytes(node);
        folderMap.set(currentPath, total);
      }
    }
  }
  return Array.from(folderMap.entries()).filter(([_, bytes]) => bytes >= minBytes).map(([path, bytes]) => [path.slice(1), bytes]);
}
```