docs: function product(subscribe) {
    const processProduct$ = productReceived$.merge(cachedProductReceived$);
  
    subscribe(productWillEnter$, ({ action, dispatch }) => {
      const { productId } = action.route.params;
      const { productId: variantId } = action.route.state;
      const id = variantId || hex2bin(productId);
  
      dispatch(fetchProduct(id));
      dispatch(fetchProductDescription(id));
      dispatch(fetchProductProperties(id));
      dispatch(fetchProductImages(id, productImageFormats.getAllUniqueFormats()));
      dispatch(fetchProductShipping(id));
    });
  
    subscribe(processProduct$, ({ action, dispatch }) => {
      const {
        id,
        flags = {
          hasVariants: false,
          hasOptions: false,
        },
        baseProductId,
      } = action.productData;
  
      if (baseProductId) {
        dispatch(fetchProduct(baseProductId));
        dispatch(fetchProductImages(baseProductId, productImageFormats.getAllUniqueFormats()));
      }
  
      if (flags.hasVariants) {
        dispatch(fetchProductVariants(id));
      }
  
      if (flags.hasOptions) {
        dispatch(fetchProductOptions(id));
      }
    });
  
    const receivedVisibleProductDebounced$ = receivedVisibleProduct$.debounceTime(500);
    /** Refresh product data after getting cache version for PDP */
    subscribe(receivedVisibleProductDebounced$, ({ action, dispatch }) => {
      const { id } = action.productData;
      dispatch(fetchProduct(id, true));
    });
  
    /** Visible product is no more available */
    subscribe(visibleProductNotFound$, ({ action, dispatch }) => {
      dispatch(showModal({
        confirm: null,
        dismiss: 'modal.ok',
        title: 'modal.title_error',
        message: 'product.no_more_found',
        params: {
          name: action.productData.name,
        },
      }));
      dispatch(historyPop());
      dispatch(expireProductById(action.productData.id));
    });
  
    subscribe(productRelationsReceived$, ({ dispatch, getState, action }) => {
      const { hash } = action;
      const productIds = getProductRelationsByHash(hash)(getState());
  
      dispatch(fetchProductsById(productIds));
    });
  
    /**
     * Expire products after checkout, fetch updated data
     */
    subscribe(checkoutSucceeded$, ({ dispatch, action }) => {
      const { products } = action;
  
      const productIds = products.map(p => p.product.id);
      productIds.forEach(id => dispatch(expireProductById(id)));
  
      dispatch(fetchProductsById(productIds));
    });
  }