 function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { snooze } from './snooze'



export async function asyncWaterfall(
  asyncFuncs,
  timeoutMs = 5000
) {
  let pending = asyncFuncs.length
  const promises = []
  for (const func of asyncFuncs) {
    const index = promises.length
    promises.push(
      func().catch(e => {
        e.index = index
        throw e
      })
    )
    if (pending > 1) {
      promises.push(
        new Promise(resolve => {
          snooze(timeoutMs)
            .then(() => {
              resolve('async_waterfall_timed_out')
            })
            .catch(_ => {})
        })
      )
    }
    try {
      const result = await Promise.race(promises)
      if (result === 'async_waterfall_timed_out') {
        const p = promises.pop()
        _optionalChain([p, 'optionalAccess', _2 => _2.catch, 'call', _3 => _3(_ => {})])
        --pending
      } else {
        return result
      }
    } catch (e) {
      const i = e.index
      promises.splice(i, 1)
      const p = promises.pop()
      _optionalChain([p, 'optionalAccess', _4 => _4.catch, 'call', _5 => _5(_ => {})])
      --pending
      if (pending === 0) {
        throw e
      }
    }
  }
}
