/**
 * Like `Promise.allSettled()` but throws an error if any promises are rejected.
 * Rejection reasons remain available on the thrown error's non-enumerable `rejections`
 * property without being written to the global console.
 */
export const allSettledWithThrow = async <R>(promises: Promise<R>[]): Promise<R[]> => {
  const results = await Promise.allSettled(promises);
  const rejected = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected');
  if (rejected.length) {
    throw Object.defineProperty(new Error(`${rejected.length} promise(s) failed`), 'rejections', {
      configurable: true,
      value: rejected.map(({ reason }) => reason),
      writable: true,
    });
  }

  // Note: TS was complaining about using `.filter().map()` here for some reason
  const values: R[] = [];
  for (const result of results) {
    if (result.status === 'fulfilled') {
      values.push(result.value);
    }
  }
  return values;
};
