How to retrieve async data in a custom hits widget

Hello,

I’m trying to write a custom hits display widget that will cycle through all Shopify products that have a colour option and will then make a call to the Shopify API to retrieve the additional product variants. However, since this is an async function, the UI ends up displaying [object Promise] for each hit instead of rendering the widget. My code is as follows:

import algoliasearch, { SearchClient } from 'algoliasearch/lite';
import instantsearch from 'instantsearch.js';
import { connectSortBy, connectHits } from 'instantsearch.js/es/connectors';
import {
  stats,
  toggleRefinement,
  rangeSlider,
  refinementList,
  pagination,
} from 'instantsearch.js/es/widgets';

import { formatAsMoney } from '../../modules/utils';

const searchClient = algoliasearch(
  'appID',
  'appKey'
);

const renderHits = (renderOptions, isFirstRender) => {
  const { hits, widgetParams } = renderOptions;

  let innerHtml = hits.map(async (hit) => {
    let images: any[] = [];

    images.push({ url: hit.product_image, class: 'primary' });

    let imageHTML = images.map((image) => {
      return `<img
          class="product-card__img product-card__img--${image.class} lazyload"
          data-src="${image.url}"
          />`;
    });

    // variants should only show for colour options, not size etc.
    // We're showing 3, and if there are more than that the plus button shows
    let variantsHTML = '';

    // Check if there are colour or material variants for this item
    // If there is also a size available, don't show the colour picker
    if (
      (hit.option_names.includes('color') ||
        hit.option_names.includes('colour') ||
        hit.option_names.includes('material')) &&
      !hit.option_names.includes('size')
    ) {
      // Make a call to get the variants
      const { html } = await fetch(`/api/shop/variant-colours/${hit.id}`).then(
        (r) => r.json()
      );

      // Build the HTML
      variantsHTML = `<div role="group" aria-labelledby="option-label_colour" class="variant-selectors variant-selectors--mini">

        <span class="sr-only" id="option-label__colour">Select a Colour</span>
        <div class="variant-selectors__buttons">
              ${html}

              <span class="variant-selectors__additional"></span>
        </div>
      </div>`;
    }

    return ` 
      <li class="collection__grid-item">  
        <div class="product-card js-product" data-product="${hit.handle}">
            <a href="/products/${hit.handle}" class="product-card__images"
              >${imageHTML}</a
            >

            <div class="product-card__details">
              <h3 class="product-card__title">${hit.title}</h3>
              <p class="product-card__price js-product-price">
                $${hit.price.toLocaleString('en-US')}
              </p>
            </div>

            <div class="product-card__btns">
              <button class="bag-btn product-card__add-to-cart js-add-to-cart" data-id="gid://shopify/ProductVariant/${
                hit.objectID
              }">
                <span class="sr-only">Add to Cart</span>
              </button>
              ${variantsHTML}
            </div>
          
          </div>
        </li>
        `;
  });

  widgetParams.container.innerHTML = `<ol class="collection__grid">${innerHtml.join(
    ''
  )}</ol>`;
};

const customHits = connectHits(renderHits);

function init(searchClient: SearchClient) {
  const search = instantsearch({
    indexName: 'shopify_products',
    routing: true,
    searchClient,
  });

  document.addEventListener('DOMContentLoaded', () => {
    search.addWidgets([
      customHits({
        container: document.querySelector('#hits'),
      }),
    ]);
  });

  search.start();
}

init(searchClient);

This is being built using the AdonisJS framework. Any help on what I’m missing would be appreciated. Thanks!