Index: vendor/guzzlehttp/promises/src/AggregateException.php
===================================================================
--- vendor/guzzlehttp/promises/src/AggregateException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/AggregateException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Exception thrown when too many errors occur in the some() or any() methods.
+ */
+class AggregateException extends RejectionException
+{
+    public function __construct(string $msg, array $reasons)
+    {
+        parent::__construct(
+            $reasons,
+            sprintf('%s; %d rejected promises', $msg, count($reasons))
+        );
+    }
+}
Index: vendor/guzzlehttp/promises/src/CancellationException.php
===================================================================
--- vendor/guzzlehttp/promises/src/CancellationException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/CancellationException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Exception that is set as the reason for a promise that has been cancelled.
+ */
+class CancellationException extends RejectionException
+{
+}
Index: vendor/guzzlehttp/promises/src/Coroutine.php
===================================================================
--- vendor/guzzlehttp/promises/src/Coroutine.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Coroutine.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,162 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+use Generator;
+use Throwable;
+
+/**
+ * Creates a promise that is resolved using a generator that yields values or
+ * promises (somewhat similar to C#'s async keyword).
+ *
+ * When called, the Coroutine::of method will start an instance of the generator
+ * and returns a promise that is fulfilled with its final yielded value.
+ *
+ * Control is returned back to the generator when the yielded promise settles.
+ * This can lead to less verbose code when doing lots of sequential async calls
+ * with minimal processing in between.
+ *
+ *     use GuzzleHttp\Promise;
+ *
+ *     function createPromise($value) {
+ *         return new Promise\FulfilledPromise($value);
+ *     }
+ *
+ *     $promise = Promise\Coroutine::of(function () {
+ *         $value = (yield createPromise('a'));
+ *         try {
+ *             $value = (yield createPromise($value . 'b'));
+ *         } catch (\Throwable $e) {
+ *             // The promise was rejected.
+ *         }
+ *         yield $value . 'c';
+ *     });
+ *
+ *     // Outputs "abc"
+ *     $promise->then(function ($v) { echo $v; });
+ *
+ * @param callable $generatorFn Generator function to wrap into a promise.
+ *
+ * @return Promise
+ *
+ * @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
+ */
+final class Coroutine implements PromiseInterface
+{
+    /**
+     * @var PromiseInterface|null
+     */
+    private $currentPromise;
+
+    /**
+     * @var Generator
+     */
+    private $generator;
+
+    /**
+     * @var Promise
+     */
+    private $result;
+
+    public function __construct(callable $generatorFn)
+    {
+        $this->generator = $generatorFn();
+        $this->result = new Promise(function (): void {
+            while (isset($this->currentPromise)) {
+                $this->currentPromise->wait();
+            }
+        });
+        try {
+            $this->nextCoroutine($this->generator->current());
+        } catch (Throwable $throwable) {
+            $this->result->reject($throwable);
+        }
+    }
+
+    /**
+     * Create a new coroutine.
+     */
+    public static function of(callable $generatorFn): self
+    {
+        return new self($generatorFn);
+    }
+
+    public function then(
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        return $this->result->then($onFulfilled, $onRejected);
+    }
+
+    public function otherwise(callable $onRejected): PromiseInterface
+    {
+        return $this->result->otherwise($onRejected);
+    }
+
+    public function wait(bool $unwrap = true)
+    {
+        return $this->result->wait($unwrap);
+    }
+
+    public function getState(): string
+    {
+        return $this->result->getState();
+    }
+
+    public function resolve($value): void
+    {
+        $this->result->resolve($value);
+    }
+
+    public function reject($reason): void
+    {
+        $this->result->reject($reason);
+    }
+
+    public function cancel(): void
+    {
+        $this->currentPromise->cancel();
+        $this->result->cancel();
+    }
+
+    private function nextCoroutine($yielded): void
+    {
+        $this->currentPromise = Create::promiseFor($yielded)
+            ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
+    }
+
+    /**
+     * @internal
+     */
+    public function _handleSuccess($value): void
+    {
+        unset($this->currentPromise);
+        try {
+            $next = $this->generator->send($value);
+            if ($this->generator->valid()) {
+                $this->nextCoroutine($next);
+            } else {
+                $this->result->resolve($value);
+            }
+        } catch (Throwable $throwable) {
+            $this->result->reject($throwable);
+        }
+    }
+
+    /**
+     * @internal
+     */
+    public function _handleFailure($reason): void
+    {
+        unset($this->currentPromise);
+        try {
+            $nextYield = $this->generator->throw(Create::exceptionFor($reason));
+            // The throw was caught, so keep iterating on the coroutine
+            $this->nextCoroutine($nextYield);
+        } catch (Throwable $throwable) {
+            $this->result->reject($throwable);
+        }
+    }
+}
Index: vendor/guzzlehttp/promises/src/Create.php
===================================================================
--- vendor/guzzlehttp/promises/src/Create.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Create.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+final class Create
+{
+    /**
+     * Creates a promise for a value if the value is not a promise.
+     *
+     * @param mixed $value Promise or value.
+     */
+    public static function promiseFor($value): PromiseInterface
+    {
+        if ($value instanceof PromiseInterface) {
+            return $value;
+        }
+
+        // Return a Guzzle promise that shadows the given promise.
+        if (is_object($value) && method_exists($value, 'then')) {
+            $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
+            $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
+            $promise = new Promise($wfn, $cfn);
+            $value->then([$promise, 'resolve'], [$promise, 'reject']);
+
+            return $promise;
+        }
+
+        return new FulfilledPromise($value);
+    }
+
+    /**
+     * Creates a rejected promise for a reason if the reason is not a promise.
+     * If the provided reason is a promise, then it is returned as-is.
+     *
+     * @param mixed $reason Promise or reason.
+     */
+    public static function rejectionFor($reason): PromiseInterface
+    {
+        if ($reason instanceof PromiseInterface) {
+            return $reason;
+        }
+
+        return new RejectedPromise($reason);
+    }
+
+    /**
+     * Create an exception for a rejected promise value.
+     *
+     * @param mixed $reason
+     */
+    public static function exceptionFor($reason): \Throwable
+    {
+        if ($reason instanceof \Throwable) {
+            return $reason;
+        }
+
+        return new RejectionException($reason);
+    }
+
+    /**
+     * Returns an iterator for the given value.
+     *
+     * @param mixed $value
+     */
+    public static function iterFor($value): \Iterator
+    {
+        if ($value instanceof \Iterator) {
+            return $value;
+        }
+
+        if (is_array($value)) {
+            return new \ArrayIterator($value);
+        }
+
+        return new \ArrayIterator([$value]);
+    }
+}
Index: vendor/guzzlehttp/promises/src/Each.php
===================================================================
--- vendor/guzzlehttp/promises/src/Each.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Each.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+final class Each
+{
+    /**
+     * Given an iterator that yields promises or values, returns a promise that
+     * is fulfilled with a null value when the iterator has been consumed or
+     * the aggregate promise has been fulfilled or rejected.
+     *
+     * $onFulfilled is a function that accepts the fulfilled value, iterator
+     * index, and the aggregate promise. The callback can invoke any necessary
+     * side effects and choose to resolve or reject the aggregate if needed.
+     *
+     * $onRejected is a function that accepts the rejection reason, iterator
+     * index, and the aggregate promise. The callback can invoke any necessary
+     * side effects and choose to resolve or reject the aggregate if needed.
+     *
+     * @param mixed $iterable Iterator or array to iterate over.
+     */
+    public static function of(
+        $iterable,
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        return (new EachPromise($iterable, [
+            'fulfilled' => $onFulfilled,
+            'rejected' => $onRejected,
+        ]))->promise();
+    }
+
+    /**
+     * Like of, but only allows a certain number of outstanding promises at any
+     * given time.
+     *
+     * $concurrency may be an integer or a function that accepts the number of
+     * pending promises and returns a numeric concurrency limit value to allow
+     * for dynamic a concurrency size.
+     *
+     * @param mixed        $iterable
+     * @param int|callable $concurrency
+     */
+    public static function ofLimit(
+        $iterable,
+        $concurrency,
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        return (new EachPromise($iterable, [
+            'fulfilled' => $onFulfilled,
+            'rejected' => $onRejected,
+            'concurrency' => $concurrency,
+        ]))->promise();
+    }
+
+    /**
+     * Like limit, but ensures that no promise in the given $iterable argument
+     * is rejected. If any promise is rejected, then the aggregate promise is
+     * rejected with the encountered rejection.
+     *
+     * @param mixed        $iterable
+     * @param int|callable $concurrency
+     */
+    public static function ofLimitAll(
+        $iterable,
+        $concurrency,
+        ?callable $onFulfilled = null
+    ): PromiseInterface {
+        return self::ofLimit(
+            $iterable,
+            $concurrency,
+            $onFulfilled,
+            function ($reason, $idx, PromiseInterface $aggregate): void {
+                $aggregate->reject($reason);
+            }
+        );
+    }
+}
Index: vendor/guzzlehttp/promises/src/EachPromise.php
===================================================================
--- vendor/guzzlehttp/promises/src/EachPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/EachPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,248 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Represents a promise that iterates over many promises and invokes
+ * side-effect functions in the process.
+ *
+ * @final
+ */
+class EachPromise implements PromisorInterface
+{
+    private $pending = [];
+
+    private $nextPendingIndex = 0;
+
+    /** @var \Iterator|null */
+    private $iterable;
+
+    /** @var callable|int|null */
+    private $concurrency;
+
+    /** @var callable|null */
+    private $onFulfilled;
+
+    /** @var callable|null */
+    private $onRejected;
+
+    /** @var Promise|null */
+    private $aggregate;
+
+    /** @var bool|null */
+    private $mutex;
+
+    /**
+     * Configuration hash can include the following key value pairs:
+     *
+     * - fulfilled: (callable) Invoked when a promise fulfills. The function
+     *   is invoked with three arguments: the fulfillment value, the index
+     *   position from the iterable list of the promise, and the aggregate
+     *   promise that manages all of the promises. The aggregate promise may
+     *   be resolved from within the callback to short-circuit the promise.
+     * - rejected: (callable) Invoked when a promise is rejected. The
+     *   function is invoked with three arguments: the rejection reason, the
+     *   index position from the iterable list of the promise, and the
+     *   aggregate promise that manages all of the promises. The aggregate
+     *   promise may be resolved from within the callback to short-circuit
+     *   the promise.
+     * - concurrency: (integer) Pass this configuration option to limit the
+     *   allowed number of outstanding concurrently executing promises,
+     *   creating a capped pool of promises. There is no limit by default.
+     *
+     * @param mixed $iterable Promises or values to iterate.
+     * @param array $config   Configuration options
+     */
+    public function __construct($iterable, array $config = [])
+    {
+        $this->iterable = Create::iterFor($iterable);
+
+        if (isset($config['concurrency'])) {
+            $this->concurrency = $config['concurrency'];
+        }
+
+        if (isset($config['fulfilled'])) {
+            $this->onFulfilled = $config['fulfilled'];
+        }
+
+        if (isset($config['rejected'])) {
+            $this->onRejected = $config['rejected'];
+        }
+    }
+
+    /** @psalm-suppress InvalidNullableReturnType */
+    public function promise(): PromiseInterface
+    {
+        if ($this->aggregate) {
+            return $this->aggregate;
+        }
+
+        try {
+            $this->createPromise();
+            /** @psalm-assert Promise $this->aggregate */
+            $this->iterable->rewind();
+            $this->refillPending();
+        } catch (\Throwable $e) {
+            $this->aggregate->reject($e);
+        }
+
+        /**
+         * @psalm-suppress NullableReturnStatement
+         */
+        return $this->aggregate;
+    }
+
+    private function createPromise(): void
+    {
+        $this->mutex = false;
+        $this->aggregate = new Promise(function (): void {
+            if ($this->checkIfFinished()) {
+                return;
+            }
+            reset($this->pending);
+            // Consume a potentially fluctuating list of promises while
+            // ensuring that indexes are maintained (precluding array_shift).
+            while ($promise = current($this->pending)) {
+                next($this->pending);
+                $promise->wait();
+                if (Is::settled($this->aggregate)) {
+                    return;
+                }
+            }
+        });
+
+        // Clear the references when the promise is resolved.
+        $clearFn = function (): void {
+            $this->iterable = $this->concurrency = $this->pending = null;
+            $this->onFulfilled = $this->onRejected = null;
+            $this->nextPendingIndex = 0;
+        };
+
+        $this->aggregate->then($clearFn, $clearFn);
+    }
+
+    private function refillPending(): void
+    {
+        if (!$this->concurrency) {
+            // Add all pending promises.
+            while ($this->addPending() && $this->advanceIterator()) {
+            }
+
+            return;
+        }
+
+        // Add only up to N pending promises.
+        $concurrency = is_callable($this->concurrency)
+            ? ($this->concurrency)(count($this->pending))
+            : $this->concurrency;
+        $concurrency = max($concurrency - count($this->pending), 0);
+        // Concurrency may be set to 0 to disallow new promises.
+        if (!$concurrency) {
+            return;
+        }
+        // Add the first pending promise.
+        $this->addPending();
+        // Note this is special handling for concurrency=1 so that we do
+        // not advance the iterator after adding the first promise. This
+        // helps work around issues with generators that might not have the
+        // next value to yield until promise callbacks are called.
+        while (--$concurrency
+            && $this->advanceIterator()
+            && $this->addPending()) {
+        }
+    }
+
+    private function addPending(): bool
+    {
+        if (!$this->iterable || !$this->iterable->valid()) {
+            return false;
+        }
+
+        $promise = Create::promiseFor($this->iterable->current());
+        $key = $this->iterable->key();
+
+        // Iterable keys may not be unique, so we use a counter to
+        // guarantee uniqueness
+        $idx = $this->nextPendingIndex++;
+
+        $this->pending[$idx] = $promise->then(
+            function ($value) use ($idx, $key): void {
+                if ($this->onFulfilled) {
+                    ($this->onFulfilled)(
+                        $value,
+                        $key,
+                        $this->aggregate
+                    );
+                }
+                $this->step($idx);
+            },
+            function ($reason) use ($idx, $key): void {
+                if ($this->onRejected) {
+                    ($this->onRejected)(
+                        $reason,
+                        $key,
+                        $this->aggregate
+                    );
+                }
+                $this->step($idx);
+            }
+        );
+
+        return true;
+    }
+
+    private function advanceIterator(): bool
+    {
+        // Place a lock on the iterator so that we ensure to not recurse,
+        // preventing fatal generator errors.
+        if ($this->mutex) {
+            return false;
+        }
+
+        $this->mutex = true;
+
+        try {
+            $this->iterable->next();
+            $this->mutex = false;
+
+            return true;
+        } catch (\Throwable $e) {
+            $this->aggregate->reject($e);
+            $this->mutex = false;
+
+            return false;
+        }
+    }
+
+    private function step(int $idx): void
+    {
+        // If the promise was already resolved, then ignore this step.
+        if (Is::settled($this->aggregate)) {
+            return;
+        }
+
+        unset($this->pending[$idx]);
+
+        // Only refill pending promises if we are not locked, preventing the
+        // EachPromise to recursively invoke the provided iterator, which
+        // cause a fatal error: "Cannot resume an already running generator"
+        if ($this->advanceIterator() && !$this->checkIfFinished()) {
+            // Add more pending promises if possible.
+            $this->refillPending();
+        }
+    }
+
+    private function checkIfFinished(): bool
+    {
+        if (!$this->pending && !$this->iterable->valid()) {
+            // Resolve the promise if there's nothing left to do.
+            $this->aggregate->resolve(null);
+
+            return true;
+        }
+
+        return false;
+    }
+}
Index: vendor/guzzlehttp/promises/src/FulfilledPromise.php
===================================================================
--- vendor/guzzlehttp/promises/src/FulfilledPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/FulfilledPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,89 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise that has been fulfilled.
+ *
+ * Thenning off of this promise will invoke the onFulfilled callback
+ * immediately and ignore other callbacks.
+ *
+ * @final
+ */
+class FulfilledPromise implements PromiseInterface
+{
+    private $value;
+
+    /**
+     * @param mixed $value
+     */
+    public function __construct($value)
+    {
+        if (is_object($value) && method_exists($value, 'then')) {
+            throw new \InvalidArgumentException(
+                'You cannot create a FulfilledPromise with a promise.'
+            );
+        }
+
+        $this->value = $value;
+    }
+
+    public function then(
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        // Return itself if there is no onFulfilled function.
+        if (!$onFulfilled) {
+            return $this;
+        }
+
+        $queue = Utils::queue();
+        $p = new Promise([$queue, 'run']);
+        $value = $this->value;
+        $queue->add(static function () use ($p, $value, $onFulfilled): void {
+            if (Is::pending($p)) {
+                try {
+                    $p->resolve($onFulfilled($value));
+                } catch (\Throwable $e) {
+                    $p->reject($e);
+                }
+            }
+        });
+
+        return $p;
+    }
+
+    public function otherwise(callable $onRejected): PromiseInterface
+    {
+        return $this->then(null, $onRejected);
+    }
+
+    public function wait(bool $unwrap = true)
+    {
+        return $unwrap ? $this->value : null;
+    }
+
+    public function getState(): string
+    {
+        return self::FULFILLED;
+    }
+
+    public function resolve($value): void
+    {
+        if ($value !== $this->value) {
+            throw new \LogicException('Cannot resolve a fulfilled promise');
+        }
+    }
+
+    public function reject($reason): void
+    {
+        throw new \LogicException('Cannot reject a fulfilled promise');
+    }
+
+    public function cancel(): void
+    {
+        // pass
+    }
+}
Index: vendor/guzzlehttp/promises/src/Is.php
===================================================================
--- vendor/guzzlehttp/promises/src/Is.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Is.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+final class Is
+{
+    /**
+     * Returns true if a promise is pending.
+     */
+    public static function pending(PromiseInterface $promise): bool
+    {
+        return $promise->getState() === PromiseInterface::PENDING;
+    }
+
+    /**
+     * Returns true if a promise is fulfilled or rejected.
+     */
+    public static function settled(PromiseInterface $promise): bool
+    {
+        return $promise->getState() !== PromiseInterface::PENDING;
+    }
+
+    /**
+     * Returns true if a promise is fulfilled.
+     */
+    public static function fulfilled(PromiseInterface $promise): bool
+    {
+        return $promise->getState() === PromiseInterface::FULFILLED;
+    }
+
+    /**
+     * Returns true if a promise is rejected.
+     */
+    public static function rejected(PromiseInterface $promise): bool
+    {
+        return $promise->getState() === PromiseInterface::REJECTED;
+    }
+}
Index: vendor/guzzlehttp/promises/src/Promise.php
===================================================================
--- vendor/guzzlehttp/promises/src/Promise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Promise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,281 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Promises/A+ implementation that avoids recursion when possible.
+ *
+ * @see https://promisesaplus.com/
+ *
+ * @final
+ */
+class Promise implements PromiseInterface
+{
+    private $state = self::PENDING;
+    private $result;
+    private $cancelFn;
+    private $waitFn;
+    private $waitList;
+    private $handlers = [];
+
+    /**
+     * @param callable $waitFn   Fn that when invoked resolves the promise.
+     * @param callable $cancelFn Fn that when invoked cancels the promise.
+     */
+    public function __construct(
+        ?callable $waitFn = null,
+        ?callable $cancelFn = null
+    ) {
+        $this->waitFn = $waitFn;
+        $this->cancelFn = $cancelFn;
+    }
+
+    public function then(
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        if ($this->state === self::PENDING) {
+            $p = new Promise(null, [$this, 'cancel']);
+            $this->handlers[] = [$p, $onFulfilled, $onRejected];
+            $p->waitList = $this->waitList;
+            $p->waitList[] = $this;
+
+            return $p;
+        }
+
+        // Return a fulfilled promise and immediately invoke any callbacks.
+        if ($this->state === self::FULFILLED) {
+            $promise = Create::promiseFor($this->result);
+
+            return $onFulfilled ? $promise->then($onFulfilled) : $promise;
+        }
+
+        // It's either cancelled or rejected, so return a rejected promise
+        // and immediately invoke any callbacks.
+        $rejection = Create::rejectionFor($this->result);
+
+        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
+    }
+
+    public function otherwise(callable $onRejected): PromiseInterface
+    {
+        return $this->then(null, $onRejected);
+    }
+
+    public function wait(bool $unwrap = true)
+    {
+        $this->waitIfPending();
+
+        if ($this->result instanceof PromiseInterface) {
+            return $this->result->wait($unwrap);
+        }
+        if ($unwrap) {
+            if ($this->state === self::FULFILLED) {
+                return $this->result;
+            }
+            // It's rejected so "unwrap" and throw an exception.
+            throw Create::exceptionFor($this->result);
+        }
+    }
+
+    public function getState(): string
+    {
+        return $this->state;
+    }
+
+    public function cancel(): void
+    {
+        if ($this->state !== self::PENDING) {
+            return;
+        }
+
+        $this->waitFn = $this->waitList = null;
+
+        if ($this->cancelFn) {
+            $fn = $this->cancelFn;
+            $this->cancelFn = null;
+            try {
+                $fn();
+            } catch (\Throwable $e) {
+                $this->reject($e);
+            }
+        }
+
+        // Reject the promise only if it wasn't rejected in a then callback.
+        /** @psalm-suppress RedundantCondition */
+        if ($this->state === self::PENDING) {
+            $this->reject(new CancellationException('Promise has been cancelled'));
+        }
+    }
+
+    public function resolve($value): void
+    {
+        $this->settle(self::FULFILLED, $value);
+    }
+
+    public function reject($reason): void
+    {
+        $this->settle(self::REJECTED, $reason);
+    }
+
+    private function settle(string $state, $value): void
+    {
+        if ($this->state !== self::PENDING) {
+            // Ignore calls with the same resolution.
+            if ($state === $this->state && $value === $this->result) {
+                return;
+            }
+            throw $this->state === $state
+                ? new \LogicException("The promise is already {$state}.")
+                : new \LogicException("Cannot change a {$this->state} promise to {$state}");
+        }
+
+        if ($value === $this) {
+            throw new \LogicException('Cannot fulfill or reject a promise with itself');
+        }
+
+        // Clear out the state of the promise but stash the handlers.
+        $this->state = $state;
+        $this->result = $value;
+        $handlers = $this->handlers;
+        $this->handlers = null;
+        $this->waitList = $this->waitFn = null;
+        $this->cancelFn = null;
+
+        if (!$handlers) {
+            return;
+        }
+
+        // If the value was not a settled promise or a thenable, then resolve
+        // it in the task queue using the correct ID.
+        if (!is_object($value) || !method_exists($value, 'then')) {
+            $id = $state === self::FULFILLED ? 1 : 2;
+            // It's a success, so resolve the handlers in the queue.
+            Utils::queue()->add(static function () use ($id, $value, $handlers): void {
+                foreach ($handlers as $handler) {
+                    self::callHandler($id, $value, $handler);
+                }
+            });
+        } elseif ($value instanceof Promise && Is::pending($value)) {
+            // We can just merge our handlers onto the next promise.
+            $value->handlers = array_merge($value->handlers, $handlers);
+        } else {
+            // Resolve the handlers when the forwarded promise is resolved.
+            $value->then(
+                static function ($value) use ($handlers): void {
+                    foreach ($handlers as $handler) {
+                        self::callHandler(1, $value, $handler);
+                    }
+                },
+                static function ($reason) use ($handlers): void {
+                    foreach ($handlers as $handler) {
+                        self::callHandler(2, $reason, $handler);
+                    }
+                }
+            );
+        }
+    }
+
+    /**
+     * Call a stack of handlers using a specific callback index and value.
+     *
+     * @param int   $index   1 (resolve) or 2 (reject).
+     * @param mixed $value   Value to pass to the callback.
+     * @param array $handler Array of handler data (promise and callbacks).
+     */
+    private static function callHandler(int $index, $value, array $handler): void
+    {
+        /** @var PromiseInterface $promise */
+        $promise = $handler[0];
+
+        // The promise may have been cancelled or resolved before placing
+        // this thunk in the queue.
+        if (Is::settled($promise)) {
+            return;
+        }
+
+        try {
+            if (isset($handler[$index])) {
+                /*
+                 * If $f throws an exception, then $handler will be in the exception
+                 * stack trace. Since $handler contains a reference to the callable
+                 * itself we get a circular reference. We clear the $handler
+                 * here to avoid that memory leak.
+                 */
+                $f = $handler[$index];
+                unset($handler);
+                $promise->resolve($f($value));
+            } elseif ($index === 1) {
+                // Forward resolution values as-is.
+                $promise->resolve($value);
+            } else {
+                // Forward rejections down the chain.
+                $promise->reject($value);
+            }
+        } catch (\Throwable $reason) {
+            $promise->reject($reason);
+        }
+    }
+
+    private function waitIfPending(): void
+    {
+        if ($this->state !== self::PENDING) {
+            return;
+        } elseif ($this->waitFn) {
+            $this->invokeWaitFn();
+        } elseif ($this->waitList) {
+            $this->invokeWaitList();
+        } else {
+            // If there's no wait function, then reject the promise.
+            $this->reject('Cannot wait on a promise that has '
+                .'no internal wait function. You must provide a wait '
+                .'function when constructing the promise to be able to '
+                .'wait on a promise.');
+        }
+
+        Utils::queue()->run();
+
+        /** @psalm-suppress RedundantCondition */
+        if ($this->state === self::PENDING) {
+            $this->reject('Invoking the wait callback did not resolve the promise');
+        }
+    }
+
+    private function invokeWaitFn(): void
+    {
+        try {
+            $wfn = $this->waitFn;
+            $this->waitFn = null;
+            $wfn(true);
+        } catch (\Throwable $reason) {
+            if ($this->state === self::PENDING) {
+                // The promise has not been resolved yet, so reject the promise
+                // with the exception.
+                $this->reject($reason);
+            } else {
+                // The promise was already resolved, so there's a problem in
+                // the application.
+                throw $reason;
+            }
+        }
+    }
+
+    private function invokeWaitList(): void
+    {
+        $waitList = $this->waitList;
+        $this->waitList = null;
+
+        foreach ($waitList as $result) {
+            do {
+                $result->waitIfPending();
+                $result = $result->result;
+            } while ($result instanceof Promise);
+
+            if ($result instanceof PromiseInterface) {
+                $result->wait(false);
+            }
+        }
+    }
+}
Index: vendor/guzzlehttp/promises/src/PromiseInterface.php
===================================================================
--- vendor/guzzlehttp/promises/src/PromiseInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/PromiseInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,91 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise represents the eventual result of an asynchronous operation.
+ *
+ * The primary way of interacting with a promise is through its then method,
+ * which registers callbacks to receive either a promise’s eventual value or
+ * the reason why the promise cannot be fulfilled.
+ *
+ * @see https://promisesaplus.com/
+ */
+interface PromiseInterface
+{
+    public const PENDING = 'pending';
+    public const FULFILLED = 'fulfilled';
+    public const REJECTED = 'rejected';
+
+    /**
+     * Appends fulfillment and rejection handlers to the promise, and returns
+     * a new promise resolving to the return value of the called handler.
+     *
+     * @param callable $onFulfilled Invoked when the promise fulfills.
+     * @param callable $onRejected  Invoked when the promise is rejected.
+     */
+    public function then(
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface;
+
+    /**
+     * Appends a rejection handler callback to the promise, and returns a new
+     * promise resolving to the return value of the callback if it is called,
+     * or to its original fulfillment value if the promise is instead
+     * fulfilled.
+     *
+     * @param callable $onRejected Invoked when the promise is rejected.
+     */
+    public function otherwise(callable $onRejected): PromiseInterface;
+
+    /**
+     * Get the state of the promise ("pending", "rejected", or "fulfilled").
+     *
+     * The three states can be checked against the constants defined on
+     * PromiseInterface: PENDING, FULFILLED, and REJECTED.
+     */
+    public function getState(): string;
+
+    /**
+     * Resolve the promise with the given value.
+     *
+     * @param mixed $value
+     *
+     * @throws \RuntimeException if the promise is already resolved.
+     */
+    public function resolve($value): void;
+
+    /**
+     * Reject the promise with the given reason.
+     *
+     * @param mixed $reason
+     *
+     * @throws \RuntimeException if the promise is already resolved.
+     */
+    public function reject($reason): void;
+
+    /**
+     * Cancels the promise if possible.
+     *
+     * @see https://github.com/promises-aplus/cancellation-spec/issues/7
+     */
+    public function cancel(): void;
+
+    /**
+     * Waits until the promise completes if possible.
+     *
+     * Pass $unwrap as true to unwrap the result of the promise, either
+     * returning the resolved value or throwing the rejected exception.
+     *
+     * If the promise cannot be waited on, then the promise will be rejected.
+     *
+     * @return mixed
+     *
+     * @throws \LogicException if the promise has no wait function or if the
+     *                         promise does not settle after waiting.
+     */
+    public function wait(bool $unwrap = true);
+}
Index: vendor/guzzlehttp/promises/src/PromisorInterface.php
===================================================================
--- vendor/guzzlehttp/promises/src/PromisorInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/PromisorInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Interface used with classes that return a promise.
+ */
+interface PromisorInterface
+{
+    /**
+     * Returns a promise.
+     */
+    public function promise(): PromiseInterface;
+}
Index: vendor/guzzlehttp/promises/src/RejectedPromise.php
===================================================================
--- vendor/guzzlehttp/promises/src/RejectedPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/RejectedPromise.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise that has been rejected.
+ *
+ * Thenning off of this promise will invoke the onRejected callback
+ * immediately and ignore other callbacks.
+ *
+ * @final
+ */
+class RejectedPromise implements PromiseInterface
+{
+    private $reason;
+
+    /**
+     * @param mixed $reason
+     */
+    public function __construct($reason)
+    {
+        if (is_object($reason) && method_exists($reason, 'then')) {
+            throw new \InvalidArgumentException(
+                'You cannot create a RejectedPromise with a promise.'
+            );
+        }
+
+        $this->reason = $reason;
+    }
+
+    public function then(
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
+    ): PromiseInterface {
+        // If there's no onRejected callback then just return self.
+        if (!$onRejected) {
+            return $this;
+        }
+
+        $queue = Utils::queue();
+        $reason = $this->reason;
+        $p = new Promise([$queue, 'run']);
+        $queue->add(static function () use ($p, $reason, $onRejected): void {
+            if (Is::pending($p)) {
+                try {
+                    // Return a resolved promise if onRejected does not throw.
+                    $p->resolve($onRejected($reason));
+                } catch (\Throwable $e) {
+                    // onRejected threw, so return a rejected promise.
+                    $p->reject($e);
+                }
+            }
+        });
+
+        return $p;
+    }
+
+    public function otherwise(callable $onRejected): PromiseInterface
+    {
+        return $this->then(null, $onRejected);
+    }
+
+    public function wait(bool $unwrap = true)
+    {
+        if ($unwrap) {
+            throw Create::exceptionFor($this->reason);
+        }
+
+        return null;
+    }
+
+    public function getState(): string
+    {
+        return self::REJECTED;
+    }
+
+    public function resolve($value): void
+    {
+        throw new \LogicException('Cannot resolve a rejected promise');
+    }
+
+    public function reject($reason): void
+    {
+        if ($reason !== $this->reason) {
+            throw new \LogicException('Cannot reject a rejected promise');
+        }
+    }
+
+    public function cancel(): void
+    {
+        // pass
+    }
+}
Index: vendor/guzzlehttp/promises/src/RejectionException.php
===================================================================
--- vendor/guzzlehttp/promises/src/RejectionException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/RejectionException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A special exception that is thrown when waiting on a rejected promise.
+ *
+ * The reason value is available via the getReason() method.
+ */
+class RejectionException extends \RuntimeException
+{
+    /** @var mixed Rejection reason. */
+    private $reason;
+
+    /**
+     * @param mixed       $reason      Rejection reason.
+     * @param string|null $description Optional description.
+     */
+    public function __construct($reason, ?string $description = null)
+    {
+        $this->reason = $reason;
+
+        $message = 'The promise was rejected';
+
+        if ($description) {
+            $message .= ' with reason: '.$description;
+        } elseif (is_string($reason)
+            || (is_object($reason) && method_exists($reason, '__toString'))
+        ) {
+            $message .= ' with reason: '.$this->reason;
+        } elseif ($reason instanceof \JsonSerializable) {
+            $message .= ' with reason: '.json_encode($this->reason, JSON_PRETTY_PRINT);
+        }
+
+        parent::__construct($message);
+    }
+
+    /**
+     * Returns the rejection reason.
+     *
+     * @return mixed
+     */
+    public function getReason()
+    {
+        return $this->reason;
+    }
+}
Index: vendor/guzzlehttp/promises/src/TaskQueue.php
===================================================================
--- vendor/guzzlehttp/promises/src/TaskQueue.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/TaskQueue.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,71 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A task queue that executes tasks in a FIFO order.
+ *
+ * This task queue class is used to settle promises asynchronously and
+ * maintains a constant stack size. You can use the task queue asynchronously
+ * by calling the `run()` function of the global task queue in an event loop.
+ *
+ *     GuzzleHttp\Promise\Utils::queue()->run();
+ *
+ * @final
+ */
+class TaskQueue implements TaskQueueInterface
+{
+    private $enableShutdown = true;
+    private $queue = [];
+
+    public function __construct(bool $withShutdown = true)
+    {
+        if ($withShutdown) {
+            register_shutdown_function(function (): void {
+                if ($this->enableShutdown) {
+                    // Only run the tasks if an E_ERROR didn't occur.
+                    $err = error_get_last();
+                    if (!$err || ($err['type'] ^ E_ERROR)) {
+                        $this->run();
+                    }
+                }
+            });
+        }
+    }
+
+    public function isEmpty(): bool
+    {
+        return !$this->queue;
+    }
+
+    public function add(callable $task): void
+    {
+        $this->queue[] = $task;
+    }
+
+    public function run(): void
+    {
+        while ($task = array_shift($this->queue)) {
+            /** @var callable $task */
+            $task();
+        }
+    }
+
+    /**
+     * The task queue will be run and exhausted by default when the process
+     * exits IFF the exit is not the result of a PHP E_ERROR error.
+     *
+     * You can disable running the automatic shutdown of the queue by calling
+     * this function. If you disable the task queue shutdown process, then you
+     * MUST either run the task queue (as a result of running your event loop
+     * or manually using the run() method) or wait on each outstanding promise.
+     *
+     * Note: This shutdown will occur before any destructors are triggered.
+     */
+    public function disableShutdown(): void
+    {
+        $this->enableShutdown = false;
+    }
+}
Index: vendor/guzzlehttp/promises/src/TaskQueueInterface.php
===================================================================
--- vendor/guzzlehttp/promises/src/TaskQueueInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/TaskQueueInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+interface TaskQueueInterface
+{
+    /**
+     * Returns true if the queue is empty.
+     */
+    public function isEmpty(): bool;
+
+    /**
+     * Adds a task to the queue that will be executed the next time run is
+     * called.
+     */
+    public function add(callable $task): void;
+
+    /**
+     * Execute all of the pending task in the queue.
+     */
+    public function run(): void;
+}
Index: vendor/guzzlehttp/promises/src/Utils.php
===================================================================
--- vendor/guzzlehttp/promises/src/Utils.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/guzzlehttp/promises/src/Utils.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,261 @@
+<?php
+
+declare(strict_types=1);
+
+namespace GuzzleHttp\Promise;
+
+final class Utils
+{
+    /**
+     * Get the global task queue used for promise resolution.
+     *
+     * This task queue MUST be run in an event loop in order for promises to be
+     * settled asynchronously. It will be automatically run when synchronously
+     * waiting on a promise.
+     *
+     * <code>
+     * while ($eventLoop->isRunning()) {
+     *     GuzzleHttp\Promise\Utils::queue()->run();
+     * }
+     * </code>
+     *
+     * @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
+     */
+    public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
+    {
+        static $queue;
+
+        if ($assign) {
+            $queue = $assign;
+        } elseif (!$queue) {
+            $queue = new TaskQueue();
+        }
+
+        return $queue;
+    }
+
+    /**
+     * Adds a function to run in the task queue when it is next `run()` and
+     * returns a promise that is fulfilled or rejected with the result.
+     *
+     * @param callable $task Task function to run.
+     */
+    public static function task(callable $task): PromiseInterface
+    {
+        $queue = self::queue();
+        $promise = new Promise([$queue, 'run']);
+        $queue->add(function () use ($task, $promise): void {
+            try {
+                if (Is::pending($promise)) {
+                    $promise->resolve($task());
+                }
+            } catch (\Throwable $e) {
+                $promise->reject($e);
+            }
+        });
+
+        return $promise;
+    }
+
+    /**
+     * Synchronously waits on a promise to resolve and returns an inspection
+     * state array.
+     *
+     * Returns a state associative array containing a "state" key mapping to a
+     * valid promise state. If the state of the promise is "fulfilled", the
+     * array will contain a "value" key mapping to the fulfilled value of the
+     * promise. If the promise is rejected, the array will contain a "reason"
+     * key mapping to the rejection reason of the promise.
+     *
+     * @param PromiseInterface $promise Promise or value.
+     */
+    public static function inspect(PromiseInterface $promise): array
+    {
+        try {
+            return [
+                'state' => PromiseInterface::FULFILLED,
+                'value' => $promise->wait(),
+            ];
+        } catch (RejectionException $e) {
+            return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
+        } catch (\Throwable $e) {
+            return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
+        }
+    }
+
+    /**
+     * Waits on all of the provided promises, but does not unwrap rejected
+     * promises as thrown exception.
+     *
+     * Returns an array of inspection state arrays.
+     *
+     * @see inspect for the inspection state array format.
+     *
+     * @param PromiseInterface[] $promises Traversable of promises to wait upon.
+     */
+    public static function inspectAll($promises): array
+    {
+        $results = [];
+        foreach ($promises as $key => $promise) {
+            $results[$key] = self::inspect($promise);
+        }
+
+        return $results;
+    }
+
+    /**
+     * Waits on all of the provided promises and returns the fulfilled values.
+     *
+     * Returns an array that contains the value of each promise (in the same
+     * order the promises were provided). An exception is thrown if any of the
+     * promises are rejected.
+     *
+     * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
+     *
+     * @throws \Throwable on error
+     */
+    public static function unwrap($promises): array
+    {
+        $results = [];
+        foreach ($promises as $key => $promise) {
+            $results[$key] = $promise->wait();
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given an array of promises, return a promise that is fulfilled when all
+     * the items in the array are fulfilled.
+     *
+     * The promise's fulfillment value is an array with fulfillment values at
+     * respective positions to the original array. If any promise in the array
+     * rejects, the returned promise is rejected with the rejection reason.
+     *
+     * @param mixed $promises  Promises or values.
+     * @param bool  $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
+     */
+    public static function all($promises, bool $recursive = false): PromiseInterface
+    {
+        $results = [];
+        $promise = Each::of(
+            $promises,
+            function ($value, $idx) use (&$results): void {
+                $results[$idx] = $value;
+            },
+            function ($reason, $idx, Promise $aggregate): void {
+                if (Is::pending($aggregate)) {
+                    $aggregate->reject($reason);
+                }
+            }
+        )->then(function () use (&$results) {
+            ksort($results);
+
+            return $results;
+        });
+
+        if (true === $recursive) {
+            $promise = $promise->then(function ($results) use ($recursive, &$promises) {
+                foreach ($promises as $promise) {
+                    if (Is::pending($promise)) {
+                        return self::all($promises, $recursive);
+                    }
+                }
+
+                return $results;
+            });
+        }
+
+        return $promise;
+    }
+
+    /**
+     * Initiate a competitive race between multiple promises or values (values
+     * will become immediately fulfilled promises).
+     *
+     * When count amount of promises have been fulfilled, the returned promise
+     * is fulfilled with an array that contains the fulfillment values of the
+     * winners in order of resolution.
+     *
+     * This promise is rejected with a {@see AggregateException} if the number
+     * of fulfilled promises is less than the desired $count.
+     *
+     * @param int   $count    Total number of promises.
+     * @param mixed $promises Promises or values.
+     */
+    public static function some(int $count, $promises): PromiseInterface
+    {
+        $results = [];
+        $rejections = [];
+
+        return Each::of(
+            $promises,
+            function ($value, $idx, PromiseInterface $p) use (&$results, $count): void {
+                if (Is::settled($p)) {
+                    return;
+                }
+                $results[$idx] = $value;
+                if (count($results) >= $count) {
+                    $p->resolve(null);
+                }
+            },
+            function ($reason) use (&$rejections): void {
+                $rejections[] = $reason;
+            }
+        )->then(
+            function () use (&$results, &$rejections, $count) {
+                if (count($results) !== $count) {
+                    throw new AggregateException(
+                        'Not enough promises to fulfill count',
+                        $rejections
+                    );
+                }
+                ksort($results);
+
+                return array_values($results);
+            }
+        );
+    }
+
+    /**
+     * Like some(), with 1 as count. However, if the promise fulfills, the
+     * fulfillment value is not an array of 1 but the value directly.
+     *
+     * @param mixed $promises Promises or values.
+     */
+    public static function any($promises): PromiseInterface
+    {
+        return self::some(1, $promises)->then(function ($values) {
+            return $values[0];
+        });
+    }
+
+    /**
+     * Returns a promise that is fulfilled when all of the provided promises have
+     * been fulfilled or rejected.
+     *
+     * The returned promise is fulfilled with an array of inspection state arrays.
+     *
+     * @see inspect for the inspection state array format.
+     *
+     * @param mixed $promises Promises or values.
+     */
+    public static function settle($promises): PromiseInterface
+    {
+        $results = [];
+
+        return Each::of(
+            $promises,
+            function ($value, $idx) use (&$results): void {
+                $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
+            },
+            function ($reason, $idx) use (&$results): void {
+                $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
+            }
+        )->then(function () use (&$results) {
+            ksort($results);
+
+            return $results;
+        });
+    }
+}
