src/index.js
function deepQuery(root, currentDir, lastKey, cb) {
  if (!lastKey) {
    // initial query
    return void query(root, currentDir, (err, files, dirs) => {
      if (err) return void cb(err);

      const lastKey = dirs.length > 0 ? buildLastKeyRight(currentDir, path.join(currentDir, dirs[0].Key)) : null;
      cb(null, files, [], lastKey);
    });
  }

  // resume query via lastKey
  const keyInfo = getLastKeyInfo(lastKey);
  const lastDir = keyInfo.leftToRight === false ? path.basename(keyInfo.lastDir) : null;
  const ignoreFiles = !keyInfo.leftToRight; // ignore files in nextDir if going backwards
  //console.log(`querying ${keyInfo.nextDir}, leftToRight:${keyInfo.leftToRight}, lastDir:${lastDir}, ignoreFiles:${ignoreFiles}...`)
  query(root, keyInfo.nextDir, {lastDir, ignoreFiles}, (err, files, dirs) => {
    if (err) return void cb(err); // we're done, bail

    if (dirs.length === 0) {
      // no directories to continue down, go back
      cb(null, files, [], buildLastKeyLeft(keyInfo.nextDir));
    } else {
      // contains directories, so continue searching
      cb(null, files, [], buildLastKeyRight(keyInfo.nextDir, dirs[0].Key));
    }
  });
}
function deepQuery(root, currentDir, lastKey, cb) {
  if (!lastKey) {
    // initial query
    return void query(root, currentDir, (err, files, dirs) => {
      if (err) return void cb(err);

      const lastKey = dirs.length > 0 ? buildLastKeyRight(currentDir, path.join(currentDir, dirs[0].Key)) : null;
      cb(null, files, [], lastKey);
    });
  }

  // resume query via lastKey
  const keyInfo = getLastKeyInfo(lastKey);
  const lastDir = keyInfo.leftToRight === false ? path.basename(keyInfo.lastDir) : null;
  const ignoreFiles = !keyInfo.leftToRight; // ignore files in nextDir if going backwards
  //console.log(`querying ${keyInfo.nextDir}, leftToRight:${keyInfo.leftToRight}, lastDir:${lastDir}, ignoreFiles:${ignoreFiles}...`)
  query(root, keyInfo.nextDir, {lastDir, ignoreFiles}, (err, files, dirs) => {
    if (err) return void cb(err); // we're done, bail

    if (dirs.length === 0) {
      // no directories to continue down, go back
      cb(null, files, [], buildLastKeyLeft(keyInfo.nextDir));
    } else {
      // contains directories, so continue searching
      cb(null, files, [], buildLastKeyRight(keyInfo.nextDir, dirs[0].Key));
    }
  });
}
/*
lastKey = the next directory to query, in lexical order

example structure:
a/b/c/d
a/b/x
a/b/y
a/e
a/f

# lastKey format: (+right, -left){lastDir}:{nextDir}
+:a
+a:a/b
+a/b:/a/b/c
+a/b/c:a/b/c/d
-a/b/c/d:a/b/c
-a/b/x:a/b
-a/b/y:a/b
-a/e:a
-a/f:a
-a:.
(eof, no more dirs after `a`)