[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressSearch/SearchForm.js from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component, Fragment } from 'react'
import { createPortal } from 'react-dom'
import { FormattedMessage, injectIntl } from 'react-intl'
import PropTypes from 'prop-types'
import { withScriptjs } from 'react-google-maps'
import { graphql } from 'react-apollo'
import { compose, branch, mapProps, renderComponent } from 'recompose'
import { path } from 'ramda'
import alpha2ToAlpha3 from 'country-iso-2-to-3'
import { Alert, Button, Input, Spinner } from 'vtex.styleguide'

import Autocomplete from './Autocomplete'

import { withAddress } from '../AddressContext'
import logisticsQuery from '../../queries/logistics.gql'
import getCurrentPositionPromise from '../../utils/getCurrentPositionPromise'

/**
 * Geolocation error codes. Can be found here:
 * https://developer.mozilla.org/en-US/docs/Web/API/PositionError
 */
const ERROR_POSITION_DENIED = 1
const ERROR_POSITION_UNAVAILABLE = 2
const ERROR_TIMEOUT = 3
const ERROR_ADDRESS_NOT_FOUND = 9 // custom ad hoc error code

/**
 * Component responsible for searching the user address in Google Maps API, when
 * inserting it or using navigator geolocation to get current position
 */
class SearchForm extends Component {
  static propTypes = {
    /* Google Maps Geolocation API key */
    googleMapKey: PropTypes.string,
    /* Function that will be called after updating the orderform */
    onOrderFormUpdated: PropTypes.func,
    /* Set to loading mode */
    loading: PropTypes.bool,
    country: PropTypes.string,
  }

  state = {
    address: null,
    formattedAddress: '',
    shouldDisplayNumberInput: false,
    shouldDisplayComplementInput: false,
    isLoading: false,
    inputError: null,
    inputAddressError: null,
    AlertMessage: false,
    shouldDisplayStreetInput: false,
    hasSearchedStreet: false,
  }

  constructor(props) {
    super(props)

    this.inputRefs = []
    this.form = React.createRef()
  }

  requestGoogleMapsApi = async params => {
    const { lat, long, address } = params
    const { googleMapKey } = this.props
    const baseUrl = `https://maps.googleapis.com/maps/api/geocode/json?key=${googleMapKey}&`
    let suffix = ''
    if (address) {
      suffix = `address=${address}`
    } else if (lat && long) {
      suffix = `latlng=${lat},${long}`
    }
    try {
      const response = await fetch(baseUrl + suffix)
      return await response.json()
    } catch (err) {
      return { results: [] }
    }
  }

  /* Use the navigator geolocation to get the user position and retrieve his address using Google Maps API */
  handleSetCurrentPosition = async () => {
    if (navigator.geolocation) {
      this.setState({ isLoading: true })
      try {
        const position = await getCurrentPositionPromise()
        const { latitude, longitude } = position.coords
        const parsedResponse = await this.requestGoogleMapsApi({
          lat: latitude,
          long: longitude,
        })

        if (!parsedResponse.results.length) {
          return this.setState({
            inputError: ERROR_ADDRESS_NOT_FOUND,
            isLoading: false,
          })
        }

        const place = parsedResponse.results[0]
        const newAddress = this.getParsedAddress(place)
        if (!newAddress.postalCode) {
          return this.setState({
            inputAddressError: ERROR_ADDRESS_NOT_FOUND,
            isLoading: false,
          })
        }
        this.setState({
          address: newAddress,
          shouldDisplayNumberInput: true,
          shouldDisplayComplementInput: true,
          isLoading: false,
          inputError: null,
          inputAddressError: null,
          AlertMessage: null,
          shouldDisplayStreetInput: true,
          hasSearchedStreet: true,
          formattedAddress: place.formatted_address,
        })
      } catch (error) {
        this.setState({ inputError: error, isLoading: false })
      }
    }
  }

  handleOnPlaceSelected = place => {
    const errorState = {
      AlertMessage: (
        <FormattedMessage id="store/address-locator.address-search-invalid-address" />
      ),
      address: null,
      shouldDisplayNumberInput: false,
      shouldDisplayComplementInput: false,
      isLoading: false,
      inputError: null,
      inputAddressError: null,
      shouldDisplayStreetInput: false,
      hasSearchedStreet: false,
    }
    if (!place.address_components) {
      return this.setState(errorState)
    }
    const address = this.getParsedAddress(place)

    if (!address.city) {
      return this.setState(errorState)
    }
    const isComplete = address.postalCode && address.street
    this.setState({
      address,
      formattedAddress: place.formatted_address,
      shouldDisplayNumberInput: true,
      shouldDisplayComplementInput: true,
      isLoading: false,
      inputError: null,
      inputAddressError: null,
      AlertMessage: null,
      shouldDisplayStreetInput: !isComplete,
      hasSearchedStreet: false,
    })
  }

  /**
   * The place object returned from Google Maps API has some extra informations about the address that won't be used when sending
   * to orderform. So, this function will reduce nested address information into a simpler consumable object.
   *
   * @param {Object} place The place object returned from Google Maps API
   * @returns {Object} The reduced address data with only necessary fields/information
   */
  getParsedAddress = place => {
    const parsedAddressComponents = place.address_components.reduce(
      (accumulator, address) => {
        const parsedItem = address.types.reduce(
          (accumulator, type) => ({
            ...accumulator,
            [type]: address.short_name,
          }),
          {}
        )
        return { ...accumulator, ...parsedItem }
      },
      {}
    )

    const { lat, lng } = path(['geometry', 'location'], place) || {}
    // lat and lng may come as a function or a double
    const latitude = typeof lat === 'function' ? lat() : lat
    const longitude = typeof lng === 'function' ? lng() : lng

    const address = {
      addressType: 'residential',
      city:
        parsedAddressComponents.administrative_area_level_2 ||
        parsedAddressComponents.locality,
      complement: '',
      /* Google Maps API returns Alpha-2 ISO codes, but checkout API requires Alpha-3 */
      country: alpha2ToAlpha3(parsedAddressComponents.country),
      neighborhood: parsedAddressComponents.sublocality_level_1,
      number: parsedAddressComponents.street_number || '',
      postalCode: parsedAddressComponents.postal_code,
      receiverName: '',
      state: parsedAddressComponents.administrative_area_level_1,
      street: parsedAddressComponents.route,
      geoCoordinates: latitude && longitude ? [longitude, latitude] : null,
    }

    return address
  }

  checkAddressWithGoogle = async () => {
    const { address } = this.state
    try {
      const parsedResponse = await this.requestGoogleMapsApi({
        address: `${address.street} ${address.number}`,
      })
      if (!parsedResponse.results.length) {
        return
      }

      const place = parsedResponse.results[0]
      const googleAddress = this.getParsedAddress(place)
      if (!googleAddress.postalCode) {
        return
      }

      if (googleAddress.postalCode !== address.postalCode) {
        //  TODO use sentry to log
      }
      if (
        address.geoCoordinates[0] !== googleAddress.geoCoordinates[0] ||
        address.geoCoordinates[1] !== googleAddress.geoCoordinates[1]
      ) {
        // TODO use sentry to log
      }
      return googleAddress.geoCoordinates
    } catch (err) {
      return null
    }
  }

  handleFormSubmit = async e => {
    e.preventDefault()

    const canSubmit = this.canSubmit()

    if (!canSubmit) {
      const formElement = this.form.current
      const inputs = Array.from(
        formElement ? formElement.querySelectorAll('input') : []
      )
      for (const input of inputs) {
        if (input.value === '') {
          input.focus()
          break
        }
      }
      return
    }

    this.setState({
      isLoading: true,
      inputError: null,
      AlertMessage: null,
    })
    const { address: addressContext, onOrderFormUpdated } = this.props
    const { address } = this.state

    try {
      const googleCoords = await this.checkAddressWithGoogle()

      const response = await addressContext.updateOrderFormShipping({
        variables: {
          orderFormId: addressContext.orderForm.orderFormId,
          address: {
            ...address,
            geoCoordinates: googleCoords || address.geoCoordinates,
          },
        },
      })

      const newAddress = path(
        ['data', 'updateOrderFormShipping', 'shippingData', 'address'],
        response
      )

      if (!newAddress || !this.getIsAddressValid(newAddress)) {
        return this.setState({
          isLoading: false,
          inputError: ERROR_ADDRESS_NOT_FOUND,
        })
      }

      if (onOrderFormUpdated) {
        onOrderFormUpdated()
      }
    } catch (e) {
      this.setState({
        isLoading: false,
        AlertMessage: (
          <FormattedMessage id="store/address-locator.graphql-error" />
        ),
      })
    }
  }

  getIsAddressValid = address =>
    address.city && address.street && address.number

  handleAddressKeyChanged = (e, key) => {
    const { address } = this.state
    if (!address) return
    address[key] = e.target.value
    this.setState({ address })
  }

  handleAddressChanged = e =>
    this.setState({
      address: undefined,
      formattedAddress: e.target.value,
    })

  handleCloseAlert = () => this.setState({ AlertMessage: null })

  canUsePortal = () => Boolean(document && document.body)

  getErrorMessage = errorCode => {
    switch (errorCode) {
      case ERROR_ADDRESS_NOT_FOUND:
        return (
          <FormattedMessage id="store/address-locator.address-search-not-found-error" />
        )
      case ERROR_TIMEOUT:
        return (
          <FormattedMessage id="store/address-locator.address-search-timeout-error" />
        )
      case ERROR_POSITION_UNAVAILABLE:
        return (
          <FormattedMessage id="store/address-locator.address-search-position-unavailable-error" />
        )
      case ERROR_POSITION_DENIED:
        return (
          <FormattedMessage id="store/address-locator.address-search-position-denied-error" />
        )
      default:
        return null
    }
  }

  renderExtraDataInput = (field, type) => {
    const { address } = this.state
    const {
      intl: { formatMessage },
    } = this.props
    if (!address) return null

    return (
      <div className="mb4">
        <Input
          type={type}
          value={address[field]}
          placeholder={formatMessage({
            id: `store/address-locator.address-search-${field}-placeholder`,
          })}
          size="large"
          label={formatMessage({
            id: `store/address-locator.address-search-${field}-label`,
          })}
          onChange={e => this.handleAddressKeyChanged(e, field)}
        />
      </div>
    )
  }

  canSubmit = () => {
    const { address } = this.state
    return address && address.number && address.street
  }

  render() {
    const {
      formattedAddress,
      isLoading,
      inputError,
      AlertMessage,
      shouldDisplayStreetInput,
      hasSearchedStreet,
      shouldDisplayNumberInput,
      shouldDisplayComplementInput,
    } = this.state
    const { loading: isDisabled, country } = this.props

    return (
      <Fragment>
        {AlertMessage &&
          this.canUsePortal() &&
          createPortal(
            <div className="fixed top-0 z-max">
              <Alert type="warning" onClose={this.handleCloseAlert}>
                {AlertMessage}
              </Alert>
            </div>,
            document.body
          )}
        <form
          className="address-search w-100"
          ref={this.form}
          onSubmit={this.handleFormSubmit}
        >
          <div className="mb4">
            {!hasSearchedStreet && (
              <div className="mb4">
                <div className="relative input--icon-right">
                  <Autocomplete
                    isLoading={isDisabled}
                    onPlaceSelected={this.handleOnPlaceSelected}
                    types={['address']}
                    componentRestrictions={{ country }}
                    value={formattedAddress}
                    errorMessage={this.getErrorMessage(inputError)}
                    onChange={this.handleAddressChanged}
                    onSuffixPress={this.handleSetCurrentPosition}
                    hideLabel
                  />
                </div>
              </div>
            )}

            {shouldDisplayStreetInput &&
              hasSearchedStreet &&
              this.renderExtraDataInput('street', 'text')}
            {shouldDisplayStreetInput &&
              hasSearchedStreet &&
              this.renderExtraDataInput('neighborhood', 'text')}
            {shouldDisplayStreetInput &&
              hasSearchedStreet &&
              this.renderExtraDataInput('postalCode', 'text')}
            {shouldDisplayNumberInput &&
              this.renderExtraDataInput('number', 'number')}
            {shouldDisplayComplementInput &&
              this.renderExtraDataInput('complement', 'text')}
          </div>
          <Button className="w-100" type="submit" isLoading={isLoading} block>
            <FormattedMessage id="store/address-locator.address-search-button" />
          </Button>
        </form>
      </Fragment>
    )
  }
}

const LoadingSpinner = () => (
  <div className="flex flex-grow-1 justify-center items-center">
    <Spinner />
  </div>
)

export default compose(
  graphql(logisticsQuery, {
    name: 'logisticsQuery',
  }),
  branch(
    props => !props.logisticsQuery.loading,
    compose(
      mapProps(ownerProps => {
        const { googleMapsKey } = ownerProps.logisticsQuery.logistics
        const {
          onOrderFormUpdated,
          updateOrderFormMutation,
          country,
        } = ownerProps

        return {
          googleMapKey: googleMapsKey,
          googleMapURL: `https://maps.googleapis.com/maps/api/js?key=${googleMapsKey}&v=3.exp&libraries=places`,
          loadingElement: <SearchForm loading />,
          onOrderFormUpdated: onOrderFormUpdated,
          country,
          updateOrderFormMutation,
        }
      }),
      withScriptjs
    ),
    renderComponent(LoadingSpinner)
  ),
  withAddress,
  injectIntl
)(SearchForm)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressSearch/index.js from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'

import SearchForm from './SearchForm'

const AddressSearch = ({ onUpdateOrderForm }) => {
  const {
    culture: { country },
  } = useRuntime()

  return (
    <div className="vtex-address-modal__address">
      <h1 className="t-heading-1 mt0 mb4 mb7-ns">
        <FormattedMessage id="store/address-locator.address-page-title" />
      </h1>
      <SearchForm onOrderFormUpdated={onUpdateOrderForm} country={country} />
      <hr className="mv5 mv6-ns bg-muted-3 bn" style={{ height: 1 }} />
    </div>
  )
}

AddressSearch.propTypes = {
  onUpdateOrderForm: PropTypes.func.isRequired,
}

export default AddressSearch

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressSearch/Autocomplete.js from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'
import { Input } from 'vtex.styleguide'
import { injectIntl } from 'react-intl'

import LocationInputIcon from './LocationInputIcon'

/*

Based on: https://github.com/ErrorPro/react-google-autocomplete/blob/master/src/index.js

*/

class ReactGoogleAutocomplete extends React.Component {
  static propTypes = {
    onPlaceSelected: PropTypes.func,
    types: PropTypes.arrayOf(PropTypes.string),
    componentRestrictions: PropTypes.shape({
      country: PropTypes.string,
    }),
    bounds: PropTypes.object,
    isLoading: PropTypes.bool,
    value: PropTypes.string,
    errorMessage: PropTypes.string,
    onChange: PropTypes.func,
    onSuffixPress: PropTypes.func,
    hideLabel: PropTypes.bool,
  }

  constructor(props) {
    super(props)
    this.input = React.createRef()
    this.autocomplete = null
    this.event = null
  }

  componentDidMount() {
    if (!this.props.isLoading) {
      this.setup()
    }
  }

  setup = () => {
    const { types = ['(cities)'], componentRestrictions, bounds } = this.props
    const config = {
      types,
      bounds,
    }

    if (componentRestrictions) {
      config.componentRestrictions = componentRestrictions
    }

    this.disableAutofill()

    this.autocomplete = new google.maps.places.Autocomplete(
      this.input.current,
      config
    )

    this.event = this.autocomplete.addListener(
      'place_changed',
      this.onSelected.bind(this)
    )
  }

  componentDidUpdate(prevProps) {
    if (prevProps.isLoading && !this.props.isLoading) {
      this.setup()
    }
  }

  disableAutofill() {
    // Autofill workaround adapted from https://stackoverflow.com/questions/29931712/chrome-autofill-covers-autocomplete-for-google-maps-api-v3/49161445#49161445
    if (window.MutationObserver) {
      const observerHack = new MutationObserver(() => {
        observerHack.disconnect()
        if (this.input.current) {
          this.input.current.autocomplete = 'disable-autofill'
        }
      })
      observerHack.observe(this.input.current, {
        attributes: true,
        attributeFilter: ['autocomplete'],
      })
    }
  }

  componentWillUnmount() {
    this.event && this.event.remove()
  }

  onSelected() {
    if (this.props.onPlaceSelected) {
      this.props.onPlaceSelected(this.autocomplete.getPlace())
    }
  }

  render() {
    const {
      value,
      errorMessage,
      onChange,
      onSuffixPress,
      hideLabel,
      intl: { formatMessage },
    } = this.props

    return (
      <Input
        ref={this.input}
        key="input"
        type="text"
        value={value}
        errorMessage={errorMessage}
        placeholder={formatMessage({
          id: 'store/address-locator.address-search-placeholder',
        })}
        size="large"
        label={
          !hideLabel &&
          formatMessage({ id: 'store/address-locator.address-search-label' })
        }
        onChange={onChange}
        suffix={<LocationInputIcon onClick={onSuffixPress} />}
      />
    )
  }
}

export default injectIntl(ReactGoogleAutocomplete)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressSearch/LocationInputIcon.js from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import PropTypes from 'prop-types'

import { IconLocationInput } from 'vtex.store-icons'

const LocationInputIcon = ({ onClick }) => {
  return (
    <span
      onClick={onClick}
      className="pointer vtex-input-icon vtex-input-icon--location c-action-primary"
    >
      <IconLocationInput size={18} viewBox="0 0 18 18" />
    </span>
  )
}

LocationInputIcon.propTypes = {
  onClick: PropTypes.func,
}

export default LocationInputIcon

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressChallenge/AddressChallenge.css from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```css
@keyframes appear {
  0% {
    opacity: 0;
  }
  99% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.spinnerAppear {
  opacity: 0;
  animation: appear 3s;
  animation-fill-mode: forwards;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of address-locator/react/components/AddressChallenge/index.js from the address-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useEffect } from 'react'

import { graphql } from 'react-apollo'
import { path, compose } from 'ramda'
import { useRuntime } from 'vtex.render-runtime'
import { Spinner } from 'vtex.styleguide'
import { address as addressQuery } from 'vtex.store-resources/Queries'
import styles from './AddressChallenge.css'

const ADDRESS_PATH = '/address'

const redirectToAddress = (page, navigate) => {
  const pathName = window.location.pathname.replace(/\/$/, '')
  if (page !== 'store.address' && pathName !== ADDRESS_PATH) {
    navigate({
      fallbackToWindowLocation: false,
      query: `returnUrl=${encodeURIComponent(pathName)}`,
      page: 'store.address',
    })
  }
}

const hasShippingAddress = compose(
  Boolean,
  path(['shippingData', 'address'])
)

const AddressChallenge = ({ data, children }) => {
  const { navigate, page } = useRuntime()
  const { loading, orderForm = {}, error } = data
  const orderFormHasAddress = hasShippingAddress(orderForm)
  const hasError = !!error
  useEffect(() => {
    if (!loading && !hasError && !orderFormHasAddress) {
      redirectToAddress(page, navigate)
    }
  }, [loading, orderFormHasAddress, page, navigate, hasError])

  if (loading) {
    return (
      <div className="flex justify-center items-center absolute top-0 bottom-0 left-0 right-0 bg-base">
        <div className={styles.spinnerAppear}>
          <Spinner />
        </div>
      </div>
    )
  }
  if (!loading && orderFormHasAddress) {
    return children
  }
  return null
}

export default graphql(addressQuery, {
  options: () => ({ ssr: false }),
})(AddressChallenge)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of expertsender/docs/README.md from the expertsender VTEX app.

[Assistant]
Here's the implementation:

```markdown
# ExpertSender

Open the VTEX APP Store and install the app on your store.

or

Run the following command:

```sh
vtex install vtex.expertsender@1.x
```

Next, open the app settings on your admin and fill the form with Click Domain, `aid`, and `wid`.

### Setup in Cart and Checkout page

Open your admin in the Checkout section in the `checkout6-custom.js`:

https://ACCOUNT.myvtex.com/admin/portal/#/sites/default/code/files/checkout6-custom.js

Add the following snippet in the file and replace `"YOUR-AID"`, `"YOUR-WID"`, and `"YOUR-CLICKDOMAIN"` with the proper values:

```js
// ExpertSender
(function () {
  window.adraker = {
    aid: "YOUR-AID",
    wid: "YOUR-WID",
    clickDomain: "YOUR-CLICKDOMAIN"
  };
  var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
  g.type = 'text/javascript'; g.async = true; g.defer = true;
  g.src = "//adraker-dev.azureedge.net/web.min.js?id=" + aid + "," + wid;
  s.parentNode.insertBefore(g, s);
})();
```

Click Save.

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/utils/generateDoc.js from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```javascript
const fs = require('fs')

const { loadFilesSync } = require('@graphql-tools/load-files')
const { mergeTypeDefs } = require('@graphql-tools/merge')
const graphql = require('graphql')
const {
  loadSchemaJSON,
  renderSchema,
} = require('graphql-markdown')

const SCHEMA_PATH = `${__dirname}/../graphql/**/*.graphql`
const BUNDLE_PATH = `${__dirname}/../joined.graphql`
const MARKDOWN_PATH = `${__dirname}/../docs/README.md`

;(async () => {
  // Generate bundle
  const loadedFiles = loadFilesSync(SCHEMA_PATH)
  const typeDefs = mergeTypeDefs(loadedFiles)
  const printedTypeDefs = graphql.print(typeDefs)
  fs.writeFileSync(BUNDLE_PATH, printedTypeDefs)

  // Generate markdown
  fs.unlinkSync(MARKDOWN_PATH)
  const schema = await loadSchemaJSON(BUNDLE_PATH, { graphql })
  renderSchema(schema, {
    title: 'search-graphql',
    prologue:
      '# VTEX Search GraphQL\n\nThis app exports a GraphQL schema for search results on VTEX Stores.\n\nThe default implementation for this schema is on [vtex.search-resolver](https://github.com/vtex-apps/search-resolver) app.\n\n### Usage\n\nTo use it in your app, decalre it on your manifest file like:\n```\n"dependencies": {\n  "vtex.search-graphql": "0.x"\n}\n```\n\nYou may then use it in your front end component queries, for example, write file `productQuery.gql`:\n```graphql\nquery ProductQuery($slug: String) {\n  product(identifier: { field: slug, value: $slug}) @context(provider: "vtex.search-graphql") {\n    productName\n  }\n}\n```\n\nTo resolve this query, you need to have a app that implements the schema declared in this app, such as: [vtex.search-resolver](https://github.com/vtex-apps/search-resolver)',
    printer: (doc) => fs.appendFileSync(MARKDOWN_PATH, doc)
  })

  // Delete temp file
  fs.unlinkSync(BUNDLE_PATH)
})()

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/schema.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
enum SORT {
  ASC
  DESC
}

type Query {
  """
  Returns a specified product
  """
  product(
    """
    Product slug
    """
    slug: String
    """
    Product identifier
    """
    identifier: ProductUniqueIdentifier
    """
    Seller id encoded with base64 according to this format SW#{sellerId}
    """
    regionId: String
    """
    Trade Policy
    """
    salesChannel: Int
  ): Product @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  """
  Lists the banners registered for a given query. Check the [configuring banners documentation](https://help.vtex.com/en/tracks/vtex-intelligent-search--19wrbB7nEQcmwzDPl1l4Cb/4ViKEivLJtJsvpaW0aqIQ5) for a full explanation of the banner feature.
  """
  banners(
    """
    Search term. It can contain any character.
    """
    fullText: String = ""
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput]
  ): Banners @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  """
  Tries to correct a misspelled term from the search.
  """
  correction(
    """
    Search term. It can contain any character.
    """
    fullText: String = ""
  ): Correction @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  """
  Lists suggested terms similar to the search term.
  """
  searchSuggestions(
    """
    Search term. It can contain any character.
    """
    fullText: String!
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
  ): SearchSuggestions
    @cacheControl(scope: SEGMENT, maxAge: MEDIUM)
    @withSegment

  """
  Lists the products for a given query.
  """
  productSearch(
    """
    **Deprecated**. Use `fullText` instead.
    """
    query: String = ""
    """
    Search term. It can contain any character.
    """
    fullText: String = ""
    """
    **Deprecated**. Use `selectedFacets` instead.
    """
    map: String = ""
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput]
    """
    **Deprecated**. Use `selectedFacets` instead.
    """
    category: String = ""
    """
    **Deprecated**. Use `selectedFacets` instead.
    """
    specificationFilters: [String]
    """
    Filter by price range. e.g.: {a} TO {b} - {a} is the minimum price "from" and {b} is the highest price "to"
    """
    priceRange: String = ""
    """
    **Deprecated**. Use `selectedFacets` instead.
    """
    collection: String = ""
    """
    Filter by availability at a specific sales channel. e.g.: salesChannel:4 if want filter by available products for the sales channel 4
    """
    salesChannel: String = ""
    """
    Order by a criteria. OrderByPriceDESC/OrderByPriceASC, OrderByTopSaleDESC, OrderByReviewRateDESC, OrderByNameASC/OrderByNameDESC, OrderByReleaseDateDESC, OrderByBestDiscountDESC, OrderByScoreDESC
    If you want to sort by a specification, use the format {specification key}:{asc|desc}. For example: 'pricePerUnit:asc' or 'size:desc' (this only works on `vtex.search-resolver@1.x`)
    """
    orderBy: String = "OrderByScoreDESC"
    """
    Pagination item start
    """
    from: Int = 0
    """
    Pagination item end
    """
    to: Int = 9
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel. Will override any given salesChannel arg
    """
    hideUnavailableItems: Boolean = false
    """
    If you want faster searches and do not care about most up to date prices and promotions, use skip value.
    """
    simulationBehavior: SimulationBehavior = default
    """
    Each search engine has its own database, but this database might not have all the product information like `clusterHighlights` or `productClusters`.
    As an alternative, the search engine may use the VTEX API to complete this information by setting this field to true.
    """
    productOriginVtex: Boolean = false
    """
    Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
    """
    operator: Operator
    """
    Indicates how the search engine will correct misspelled words by using fuzzy logic.
    It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
    """
    fuzzy: String
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String

    """
    Search options that customize the search result.
    """
    options: Options
    variant: String

    """
    **Deprecated**. Use `advertisementOptions` instead.
    """
    showSponsored: Boolean

    """
    Whether or not to fetch sponsored products. If there are sponsored products for that context, it will be returned.
    """
    advertisementOptions: AdvertisementOptions
    """
    Origin of the request for tracking purposes
    """
    origin: String
  ): ProductSearch @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  sponsoredProducts(
    """
    Search term. It can contain any character.
    """
    fullText: String = ""
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput]
    """
    Filter by price range. e.g.: {a} TO {b} - {a} is the minimum price "from" and {b} is the highest price "to"
    """
    priceRange: String = ""
    """
    Filter by availability at a specific sales channel. e.g.: salesChannel:4 if want filter by available products for the sales channel 4
    """
    salesChannel: String = ""
    """
    Order by a criteria. OrderByPriceDESC/OrderByPriceASC, OrderByTopSaleDESC, OrderByReviewRateDESC, OrderByNameASC/OrderByNameDESC, OrderByReleaseDateDESC, OrderByBestDiscountDESC, OrderByScoreDESC
    If you want to sort by a specification, use the format {specification key}:{asc|desc}. For example: "pricePerUnit:asc" or "size:desc" (this only works on `vtex.search-resolver@1.x`)
    """
    orderBy: String = "OrderByScoreDESC"
    """
    Pagination item start
    """
    from: Int = 0
    """
    Pagination item end
    """
    to: Int = 9
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel. Will override any given salesChannel arg
    """
    hideUnavailableItems: Boolean = false
    """
    If you want faster searches and do not care about most up to date prices and promotions, use skip value.
    """
    simulationBehavior: SimulationBehavior = default
    """
    Each search engine has its own database, but this database might not have all the product information like `clusterHighlights` or `productClusters`.
    As an alternative, the search engine may use the VTEX API to complete this information by setting this field to true.
    """
    productOriginVtex: Boolean = false
    """
    Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
    """
    operator: Operator
    """
    Indicates how the search engine will correct misspelled words by using fuzzy logic.
    It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
    """
    fuzzy: String
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String

    """
    Search options that customize the search result.
    """
    options: Options

    """
    Identifier for users, logged in or not. Used for A/B tests.
    """
    anonymousId: String

    """
    Identifier for user device, used for analytics purposes.
    """
    macId: String

    """
    Identifier for user ID if logged in, used for analytics purposes.
    """
    userId: String
  ): [Product] @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  searchMetadata(
    """
    Terms that is used in search e.g.: eletronics/samsung
    """
    query: String = ""
    """
    Text inputted by the user as the search term
    """
    fullText: String = ""
    """
    Defines terms types: Brand, Category, Department e.g.: c,b
    """
    map: String = ""
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput]
  ): SearchMetadata @cacheControl(scope: PUBLIC, maxAge: MEDIUM) @withSegment

  """
  Returns products list filtered and ordered
  """
  products(
    """
    Terms that is used in search e.g.: eletronics/samsung
    """
    query: String = ""
    """
    Defines terms types: Brand, Category, Department e.g.: c,b
    """
    map: String = ""
    """
    Filter by category. {a}/{b} - {a} and {b} are categoryIds
    """
    category: String = ""
    """
    Array of product specification. specificationFilter_{a}:{b} - {a} is the specificationId, {b} = specification value
    """
    specificationFilters: [String]
    """
    Filter by price range. e.g.: {a} TO {b} - {a} is the minimum price "from" and {b} is the highest price "to"
    """
    priceRange: String = ""
    """
    Filter by collection. where collection also know as productClusterId
    """
    collection: String = ""
    """
    Filter by availability at a specific sales channel. e.g.: salesChannel:4 if want filter by available products for the sales channel 4
    """
    salesChannel: String = ""
    """
    Order by a criteria. OrderByPriceDESC/OrderByPriceASC, OrderByTopSaleDESC, OrderByReviewRateDESC, OrderByNameASC/OrderByNameDESC, OrderByReleaseDateDESC, OrderByBestDiscountDESC, OrderByScoreDESC
    """
    orderBy: String = "OrderByScoreDESC"
    """
    Pagination item start
    """
    from: Int = 0
    """
    Pagination item end
    """
    to: Int = 9
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel. Will override any given salesChannel arg
    """
    hideUnavailableItems: Boolean = false
    """
    If you want faster searches and do not care about most up to date prices and promotions, use skip value.
    """
    simulationBehavior: SimulationBehavior = default
    """
    List of shipping options to filter products
    """
    shippingOptions: [String]
    variant: String
    """
    Options for advertisement in this search request.
    """
    advertisementOptions: AdvertisementOptions
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
  ): [Product] @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  productRecommendations(
    identifier: ProductUniqueIdentifier
    type: CrossSelingInputEnum
    groupBy: CrossSelingGroupByEnum
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
  ): [Product] @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  productsByIdentifier(
    field: ProductUniqueIdentifierField!
    values: [ID!]
    """
    Filter by availability at a specific sales channel.
    """
    salesChannel: String
  ): [Product] @cacheControl(scope: SEGMENT, maxAge: SHORT) @withSegment

  """
  Returns facets category
  """
  facets(
    """
    **Deprecated**. Use `fullText` instead.
    """
    query: String = ""
    """
    Search term. It can contain any character.
    """
    fullText: String = ""
    """
    **Deprecated**. Use `selectedFacets` instead.
    """
    map: String = ""
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput] = []
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel.
    """
    hideUnavailableItems: Boolean = false
    """
    If true, remove hidden facets from the result.
    """
    removeHiddenFacets: Boolean = false
    """
    If Static, ignores SpecificationFilters received on the map and query when returning
    the facets available, which makes the facets never change.
    """
    behavior: String = "Static"
    """
    Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
    """
    operator: Operator
    """
    Indicates how the search engine will correct misspelled words by using fuzzy logic.
    It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
    """
    fuzzy: String
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
    """
    Pagination item start
    """
    from: Int
    """
    Pagination item end
    """
    to: Int
    """
    Determines the behavior of the category tree
    """
    categoryTreeBehavior: CategoryTreeBehavior = default
    """
    Initial attributes (based on the `initialMap` parameter)
    """
    initialAttributes: String
    """
    Variant used to A/B test
    """
    variant: String
  ): Facets @cacheControl(scope: SEGMENT, maxAge: MEDIUM) @withSegment

  """
  Get auto complete suggestions in search
  """
  autocomplete(
    """
    Number of items that is returned
    """
    maxRows: Int = 12
    """
    Terms that is used in search e.g.: iphone
    """
    searchTerm: String
  ): Suggestions @cacheControl(scope: SEGMENT, maxAge: MEDIUM) @withSegment

  """
  Get list of the 10 most searched terms
  """
  topSearches(
        """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
  ): SearchSuggestions
    @cacheControl(scope: SEGMENT, maxAge: MEDIUM)
    @withSegment

  """
  Lists the suggested terms and attributes similar to the search term.
  """
  autocompleteSearchSuggestions(
    """
    Search term. It can contain any character.
    """
    fullText: String!
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
  ): SearchSuggestions
    @cacheControl(scope: SEGMENT, maxAge: MEDIUM)
    @withSegment

  """
  Get product suggestions
  """
  productSuggestions(
    """
    Text inputted by the user as the search term
    """
    fullText: String!
    """
    Selected facet key
    """
    facetKey: String
    """
    Selected facet value
    """
    facetValue: String
    """
    Each search engine has its own database, but this database might not have all the product information like `clusterHighlights` or `productClusters`.
    As an alternative, the search engine may use the VTEX API to complete this information by setting this field to true.
    """
    productOriginVtex: Boolean = false
    """
    If you want faster searches and do not care about most up to date prices and promotions, use skip value.
    """
    simulationBehavior: SimulationBehavior = default
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel
    """
    hideUnavailableItems: Boolean
    """
    Seller id encoded with base64 according to this format SW#{sellerId}
    """
    regionId: String
    """
    Sales Channel related to the region ID
    """
    salesChannel: Int
    """
    Order by a criteria. OrderByPriceDESC/OrderByPriceASC, OrderByTopSaleDESC, OrderByReviewRateDESC, OrderByNameASC/OrderByNameDESC, OrderByReleaseDateDESC, OrderByBestDiscountDESC, OrderByScoreDESC
    If you want to sort by a specification, use the format {specification key}:{asc|desc}. For example: "pricePerUnit:asc" or "size:desc" (this only works on `vtex.search-resolver@1.x`)
    """
    orderBy: String = "OrderByScoreDESC"
    """
    Number of product suggestions that should be returned
    """
    count: Int
    """
    List of shipping options to filter suggestions
    """
    shippingOptions: [String]
    variant: String
    """
    Whether or not to fetch sponsored products. If there are sponsored products for that context, it will be returned.
    """
    advertisementOptions: AdvertisementOptions
    """
    Origin of the request for tracking purposes
    """
    origin: String
  ): ProductSuggestions
    @cacheControl(scope: SEGMENT, maxAge: MEDIUM)
    @withSegment

  """
  Get search urls access stats count
  """
  searchURLsCount(
    """
    Number of items that is returned
    """
    limit: Int = 100

    """
    Sorting strategy, asc: ascending, desc: descending
    """
    sort: SORT
  ): [SearchURLStats] @cacheControl(scope: PUBLIC, maxAge: SHORT)
}

enum SimulationBehavior {
  """
  Does simulation on catalog as usual
  """
  default
  """
  Does simulation on catalog only for seller 1P
  """
  only1P
  """
  Calls catalog passing a parameter to not simulate each SKU and get its most up to date price.
  """
  skip
  """
  Does the simulation on the client side
  """
  async
  """
  Only first party sellers will include the regionId
  """
  regionalize1p
}

enum CrossSelingGroupByEnum {
  """
  It's the default behavior, it will group SKUs from the same product and bring only products. Limited by 12 products.
  """
  PRODUCT
  """
  Return all skus registered in the catalog for the recommendation.
  """
  NONE
}

enum CategoryTreeBehavior {
  """
  Uses the default value set by the search provider
  """
  default
  """
  Show the category tree when it is possible
  """
  show
  """
  Hide the category tree in any situation
  """
  hide
}

input AdvertisementOptions {
  """
  Whether or not to fetch sponsored products in this request.
  """
  showSponsored: Boolean
  """
  How many sponsored products should be fetched.
  """
  sponsoredCount: Int
  """
  If true, the search will return the same product twice - once as a regular product and once as a sponsored product.
  """
  repeatSponsoredProducts: Boolean
  """
  Where the sponsored product is being shown. Used for analytics purposes.
  """
  advertisementPlacement: String
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/directives.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
directive @withSegment on FIELD_DEFINITION

directive @toVtexAssets on FIELD_DEFINITION

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/node/package.json from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "search-graphql",
  "description": "Don't delete this file, it's necessary to generate the TypeScript types of the GraphQL"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/ProductSearch.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type ProductSearch {
  """
  List of products.
  """
  products: [Product]
  """
  Total number of products.
  """
  recordsFiltered: Int
  """
  Title used in the title's tag.
  """
  titleTag: String
  """
  String to be used in the `<meta name="description"...` tag.
  """
  metaTagDescription: String
  breadcrumb: [SearchBreadcrumb]
    @deprecated(reason: "Use the `breadcrumb` from the `facets` query instead.")
  canonical: String
  suggestion: SearchSuggestions
    @deprecated(reason: "Use the `suggestion` query instead.")
  """
  Object that indicates if the term was misspelled and suggests a possible correction.
  """
  correction: SearchCorrection
  """
  Indicates how the search-engine dealt with the fullText when there is more than one word.\n * `and` - It means that the products contains all the words in the query.\n * `or` - It means that the results will contain at least one word from the original search query. If `and` was not possible, `or` will be the fallback.
  """
  operator: Operator
  """
  Indicates how the search engine corrected the misspelled word by using fuzzy logic. It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
  """
  fuzzy: String
  """
  As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
  The possible values in this field are defined by each search engine.
  """
  searchState: String
  banners: [SearchBanner]
    @deprecated(reason: "Use the `banners` query instead.")
  """
  Returns the redirect URL set for the given query.
  """
  redirect: String
  """
  Options to ProductSearch.
  """
  options: ProductSearchOptions
  """
  ID used to identify a search query.
  """
  searchId: String
  """
  Origin of the request for tracking purposes
  """
  origin: String
}

type ProductSearchOptions {
  """
  Indicates if delivery promises is enabled.
  """
  deliveryPromisesEnabled: Boolean
}

enum Operator {
  and
  or
}

type SearchBreadcrumb {
  """
  Human-readable format of the facet key.
  """
  name: String @translatableV2
  """
  Query link.
  """
  href: String
}

type SearchMetadata {
  titleTag: String
  metaTagDescription: String @translatableV2
}

input SelectedFacetInput {
  """
  Facet key.
  """
  key: String
  """
  Facet value.
  """
  value: String
}

type SelectedFacet {
  key: String
  value: String
}

input Options {
  """
  If the search has a redirect enabled, this allows (`true`) or not (`false`) the redirect to be used.
  """
  allowRedirect: Boolean
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/PageType.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type PageType {
  id: String
  type: PageEntityIdentifier
}

enum PageEntityIdentifier {
  brand
  department
  category
  subcategory
  search
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/SearchSuggestions.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type SearchSuggestions {
  """
  A list of search suggestions.
  """
  searches: [SearchSuggestion]
}

type SearchSuggestion {
  """
  Search term.
  """
  term: String!
  """
  Number of times the term was searched.
  """
  count: Int!
  """
  List of facets in which the term can be searched.
  """
  attributes: [SearchSuggestionAttribute]
}

type SearchSuggestionAttribute {
  """
  Facet key.
  """
  key: String!
  """
  Facet value.
  """
  value: String!
  """
  Human-readable format of the facet key.
  """
  labelValue: String!
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/SearchURLStats.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type SearchURLStats {
  path: String!
  count: Int!
}
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Brand.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Brand {
  """
   slug is used as cacheId
  """
  cacheId: ID
  """
   Brand id
  """
  id: Int
  """
   Brand logo
  """
  imageUrl: String @toVtexAssets
  """
   Text link
  """
  slug: String
  """
   Name of brand
  """
  name: String @translatableV2(behavior: "USER_ONLY")
  """
   Title used by html tag
  """
  titleTag: String @translatableV2(behavior: "USER_ONLY")
  """
   Description used by html tag
  """
  metaTagDescription: String @translatableV2
  """
   Brand is active
  """
  active: Boolean
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Facets.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type QueryArgs {
  map: String
  query: String
  selectedFacets: [SelectedFacet]
}

type Range {
  from: Float
  to: Float
}

type FacetValue {
  id: ID
  quantity: Int!
  name: String @translatableV2
  key: String
  value: String
  selected: Boolean
  children: [FacetValue]
  range: Range
  link: String
  linkEncoded: String
  href: String
}

enum FilterType {
  TEXT
  NUMBER
  CATEGORYTREE
  BRAND
  PRICERANGE
  DELIVERY
}

type Facet {
  name: String @translatableV2
  values(from: Int, to: Int): [FacetValue]
  type: FilterType
  hidden: Boolean
  quantity: Int
}

type Facets {
  departments: [DepartmentFacet]
    @deprecated(reason: "Use the `facets` instead.")
  brands: [BrandFacet] @deprecated(reason: "Use the `facets` instead.")
  specificationFilters: [FilterFacets]
  categoriesTrees: [CategoriesTreeFacet] @deprecated(reason: "Use the `facets` instead.")
  """
  Price range for the given query.
  """
  priceRanges: [PriceRangesFacet]
  recordsFiltered: Int @deprecated(reason: "Use the recordsFiltered from the `productSearch` instead.")
  """
  Info about the searched query.
  """
  queryArgs: QueryArgs
  """
  List of facets.
  """
  facets: [Facet]
  """
  Indicates whether there was sampling in the aggregation of facets or not. In search results that have many products, only the first 30000 will be aggregated to avoid performance issues.
  """
  sampling: Boolean
  """
  Generated breadcrumb for the given query.
  """
  breadcrumb: [SearchBreadcrumb]
}

type DepartmentFacet {
  id: ID!
  quantity: Int!
  name: String @translatableV2
  link: String!
  linkEncoded: String!
  map: String
  value: String!
  selected: Boolean!
}

type BrandFacet {
  id: ID!
  quantity: Int!
  name: String! @translatableV2(behavior: "USER_ONLY")
  link: String!
  linkEncoded: String!
  map: String
  value: String!
  selected: Boolean!
}

type PriceRangesFacet {
  quantity: Int!
  name: String @translatableV2
  link: String!
  linkEncoded: String!
  map: String
  value: String!
  selected: Boolean!
  slug: String
}

type CategoriesTreeFacet {
  id: ID!
  quantity: Int!
  name: String @translatableV2
  link: String!
  linkEncoded: String!
  """
  Contains slugified links according to the store structure. /:department/d, /:category/:subcategory, etc
  """
  href: String!
  map: String
  value: String!
  children: [CategoriesTreeFacet]
  selected: Boolean!
}

type FilterFacet {
  quantity: Int!
  name: String @translatableV2
  link: String!
  linkEncoded: String!
  map: String
  value: String!
  selected: Boolean!
}

type FilterFacets {
  name: String
  facets: [FilterFacet]
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Advertisement.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Advertisement {
  """
  ID of the ad item associated with the sponsored product.
  """
  adId: ID
  """
  ID of the campaign owner of the ad item.
  """
  campaignId: ID
  """
  Cost of the goal action. E.g: CPC, cost per click.
  """
  actionCost: Float
  """
  Ad Request ID.
  """
  adRequestId: ID
  """
  Ad Response ID.
  """
  adResponseId: ID
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Benefits.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
""" Benefit of a Product """
type Benefit {
  """ Flag which indicates if the benefit is featured or not """
  featured: Boolean
  """ Id of the product which the benefit is associated """
  id: String
  """ Name of the benefit """
  name: String
  """ Items of the benefit """
  items: [BenefitItem]
  """ Type of benefit """
  teaserType: String
}

type BenefitItem {
  """ Product itself """
  benefitProduct: Product
  """ IDs of the SKU Items that are taking part in the benefit """
  benefitSKUIds: [String]
  """ Discount applied to the benefit product """
  discount: Float
  """ Minimum quantity of the benefit product that is required to validate the benefit """
  minQuantity: Int
}
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Autocomplete.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type ProductSuggestions {
  """
  Number of suggested products
  """
  count: Int!
  """
  Suggested products
  """
  products: [Product]!
  """
  If the term is misspelled or not
  """
  misspelled: Boolean
  """
  Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
  """
  operator: Operator
  """
  ID used to identify a search query.
  """
  searchId: String
  """
  Origin of the request for tracking purposes
  """
  origin: String
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/ItemMetadata.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type ItemMetadata {
  items: [ItemMetadataUnit]
  priceTable: [ItemPriceTable]
}

type ItemPriceTable {
  type: String
  values: [PriceTableItem]
}

type PriceTableItem {
  id: String
  assemblyId: String
  price: Int
}

type ItemMetadataUnit {
  id: ID
  name: String
  skuName: String
  productId: String
  refId: String
  ean: String
  imageUrl: String @toVtexAssets
  detailUrl: String
  seller: String
  assemblyOptions: [AssemblyOption]
}

type AssemblyOption {
  id: ID
  name: String
  required: Boolean
  composition: CompositionType
  inputValues: [InputValue]
}

scalar StringOrBoolean

type InputValue {
  label: String
  maxLength: Int
  type: InputValueType
  defaultValue: StringOrBoolean
  domain: [String]
}

enum InputValueType {
  TEXT
  BOOLEAN
  OPTIONS
}

type CompositionType {
  minQuantity: Int
  maxQuantity: Int
  items: [CompositionItem]
}

type CompositionItem {
  id: ID
  minQuantity: Int
  maxQuantity: Int
  initialQuantity: Int
  priceTable: String
  seller: String
}

input AssemblyOptionInput {
  id: ID!
  quantity: Int!
  assemblyId: String!
  seller: String!
  options: [AssemblyOptionInput!]
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Suggestions.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Suggestions {
  """ searchTerm from Query autocomplete is used as cacheId """
  cacheId: ID
  itemsReturned: [Items]
}

type Items {
  thumb: String
  name: String @translatableV2
  href: String
  criteria: String
  slug: String
  productId: String
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Category.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Category {
  """ id is used as cacheId """
  cacheId: ID
  """ URI of category """
  href: String
  """ Category text link """
  slug: String
  """ Category ID """
  id: Int
  """ Category name """
  name: String @translatableV2
  """ Title used by html tag"""
  titleTag: String @translatableV2
  """ Description used by html tag"""
  hasChildren: Boolean
  """ Has children categories """
  metaTagDescription: String @translatableV2
  """ Categories children """
  children: [Category]
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Product.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Product {
  """
  Brand of the product
  """
  brand: String @translatableV2(behavior: "USER_ONLY")
  """
  Id of the brand of the product
  """
  brandId: Int
  """
  linkText is used as cacheId
  """
  cacheId: ID
  categoryId: ID
  """
  Categories of the product
  """
  categories: [String]
    @deprecated(
      reason: "Use 'categoryTree' field for internationalization support"
    )
  """
  Product's categories
  """
  categoryTree: [Category]
  """
  List of related products
  """
  clusterHighlights: [ClusterHighlight]
  productClusters: [ProductClusters]
  """
  Product description
  """
  description: String @translatableV2
  """
  SKU objects of the product
  """
  items(filter: ItemsFilter): [SKU]
  """
  List of SKU Specifications
  """
  skuSpecifications: [SkuSpecification]
  """
  Product URL
  """
  link: String
  """
  Product slug
  """
  linkText: String
  """
  Product ID
  """
  productId: ID
  """
  Product name
  """
  productName: String @translatableV2
  """
  Array of product properties
  """
  properties: [Property]
  """
  Array of product properties
  """
  propertyGroups: [PropertyGroup]
  """
  Product reference
  """
  productReference: String
  """
  Title used by html tag
  """
  titleTag: String @translatableV2
  """
  Description used by html tag
  """
  metaTagDescription: String @translatableV2
  """
  Related Products
  """
  recommendations(groupBy: CrossSelingGroupByEnum): Recommendation
  """
  JSON specification of the product
  """
  jsonSpecifications: String
  """
  List of benefits associated with this product
  """
  benefits: [Benefit]
  itemMetadata: ItemMetadata
  """
  Array of product SpecificationGroup
  """
  specificationGroups: [SpecificationGroup]

  """
  Returns highest and lowest prices for available SKUs in product.
  """
  priceRange: ProductPriceRange

  """
  Product Release Date, for list ordering and product cluster highlight
  """
  releaseDate: String

  """
  Product properties that will be selected by default. e.g: {key: "Color", value: "Blue"}
  """
  selectedProperties: [SelectedProperty]
  """
  Merchandising rule applied to the product
  """
  rule: Rule
  """
  If this product is sponsored, ad information will be added here.
  """
  advertisement: Advertisement
  deliveryPromisesBadges: [BadgeItem]
  specification: String
}

type BadgeItem {
  typeName: String
  pickupId: String
  pickupName: String
}

type SelectedProperty {
  key: String
  value: String
}

enum ItemsFilter {
  """
  Returns all items, same as no filter.
  """
  ALL
  """
  Returns only the first available item. Returns first if no item is available.
  """
  FIRST_AVAILABLE
  """
  Returns all available items. Returns first if no item is available.
  """
  ALL_AVAILABLE
}

type ProductPriceRange {
  sellingPrice: PriceRange
  listPrice: PriceRange
}

type PriceRange {
  highPrice: Float
  lowPrice: Float
}

type OnlyProduct {
  brand: String
  categoryId: ID
  categoryTree: [Category]
  clusterHighlights: [ClusterHighlight]
  productClusters: [ProductClusters]
  description: String
  link: String
  linkText: String
  productId: ID
  productName: String
  properties: [Property]
  propertyGroups: [PropertyGroup]
  productReference: String
  recommendations: Recommendation
  jsonSpecifications: String
}

type ProductClusters {
  id: ID
  name: String
}

type ClusterHighlight {
  id: ID
  name: String
}

type Seller {
  sellerId: ID
  sellerName: String
  addToCartLink: String
  sellerDefault: Boolean
  commertialOffer: Offer
}

type Recommendation {
  buy: [Product]
  view: [Product]
  similars: [Product]
}

type SKU {
  itemId: ID
  name: String @translatableV2
  nameComplete: String @translatableV2
  complementName: String
  ean: String
  referenceId: [Reference]
  measurementUnit: String
  unitMultiplier: Float
  kitItems: [KitItem]
  images(quantity: Int): [Image]
  videos: [Video]
  sellers: [Seller]
  variations: [Property]
  attachments: [Attachment] @deprecated(reason: "Use itemMetaData instead")
  estimatedDateArrival: String
}

type SkuSpecification {
  field: SKUSpecificationField
  values: [SKUSpecificationValue]
}

type SKUSpecificationField {
  originalName: String
  name: String @translatableV2
}

type SKUSpecificationValue {
  originalName: String
  name: String @translatableV2
}

type productSpecification {
  fieldName: String @translatableV2
  fieldValues: [String] @translatableV2
}

input ProductUniqueIdentifier {
  field: ProductUniqueIdentifierField!
  value: ID!
}

enum ProductUniqueIdentifierField {
  id
  slug
  ean
  reference
  sku
}

type KitItem {
  itemId: ID
  amount: Int
  product: OnlyProduct
  sku: SKU
}

type Attachment {
  id: ID
  name: String
  required: Boolean
  domainValues: [DomainValues]
}

type DomainValues {
  FieldName: String
  MaxCaracters: String
  DomainValues: String
}

enum InstallmentsCriteria {
  MAX_WITHOUT_INTEREST
  MAX_WITH_INTEREST
  MAX # Equivalent to MAX_WITHOUT_INTEREST. Kept for backwards-compatibility
  MIN
  ALL
}

type Offer {
  Installments(
    criteria: InstallmentsCriteria = ALL
    rates: Boolean = true
    excludedPaymentSystems: [String]
    includedPaymentSystems: [String]
  ): [Installment]
  Price: Float
  ListPrice: Float
  spotPrice: Float
  PriceWithoutDiscount: Float
  RewardValue: Float
  PriceValidUntil: String
  AvailableQuantity: Float
  Tax: Float
  taxPercentage: Float
  CacheVersionUsedToCallCheckout: String
  DeliverySlaSamples: [DeliverySlaSamples]
  """
  List of discount highlights
  """
  discountHighlights: [Discount!]
  teasers: [Teaser!]
  """
  List of SKUs for gifts associated with the product
  """
  giftSkuIds: [String]
  """
  List of gifts associated with the product
  """
  gifts: [Gift]
}

type Gift {
  productName: String
  skuName: String
  brand: String
  linkText: String
  description: String
  images: [GiftImage]
}

type GiftImage {
  imageUrl: String
  imageLabel: String
  imageText: String
}

type Teaser {
  name: String
  conditions: TeaserCondition
  effects: TeaserEffects
  generalValues: [GeneralValueTeaser]
}

type GeneralValueTeaser {
  key: String
  value: String
}

type AdditionalInfo {
  key: String
  value: String
}

type TeaserCondition {
  minimumQuantity: Int
  parameters: [TeaserValue]
}

type TeaserEffects {
  parameters: [TeaserValue]
}

type TeaserValue {
  name: String
  value: String
}

"""
Discount object
"""
type Discount {
  """
  Discount name
  """
  name: String
  """
  Additional Info
  """
  additionalInfo: [AdditionalInfo]
}

type DeliverySlaSamples {
  DeliverySlaPerTypes: [DeliverySlaPerTypes]
  Region: Region
}

type DeliverySlaPerTypes {
  TypeName: String
  Price: Float
  EstimatedTimeSpanToDelivery: String
}

type Region {
  IsPersisted: Boolean
  IsRemoved: Boolean
  Id: ID
  Name: String
  CountryCode: String
  ZipCode: String
  CultureInfoName: String
}

type Image {
  cacheId: ID
  imageId: ID
  imageLabel: String
  imageTag: String
  imageUrl: String @toVtexAssets
  imageText: String
}

type Video {
  videoUrl: String
}

type SpecificationGroup {
  originalName: String
  name: String @translatableV2
  specifications: [SpecificationGroupProperty]
}

type SpecificationGroupProperty {
  originalName: String
  name: String @translatableV2
  values: [String] @translatableV2
}

type Property {
  originalName: String
  name: String @translatableV2
  values: [String] @translatableV2
}

type PropertyGroup {
  name: String
  properties: [String]
}

type Installment {
  Value: Float
  InterestRate: Float
  TotalValuePlusInterestRate: Float
  NumberOfInstallments: Int
  PaymentSystemName: String
  PaymentSystemGroupName: String
  Name: String
}

type Reference {
  Key: String
  Value: String
}

enum CrossSelingInputEnum {
  buy
  similars
  view
  viewAndBought
  accessories
  suggestions
}

type Rule {
  id: String
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Correction.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Correction {
  correction: SearchCorrection
}

"""
Object that indicates if the term was misspelled and suggests a possible correction.
"""
type SearchCorrection {
  """
  The corrected term. If the API was not able to correct the term, it will show the original search term.
  """
  text: String
  """
  The same as `text`, but it highlights the corrected word. Useful when there is more than one word.
  """
  highlighted: String
  """
  Whether the term was misspelled (`true`) or not (`false`).
  """
  misspelled: Boolean
  """
  Whether the API was able to suggest a correction (`true`) or not (`false`).
  """
  correction: Boolean
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-graphql/graphql/types/Banners.graphql from the search-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Banners {
  """
  List of banners.
  """
  banners: [SearchBanner]
}

type SearchBanner {
  """
  Banner ID.
  """
  id: String
  """
  Banner name.
  """
  name: String
  """
  Banner area.
  """
  area: String
  """
  Banner HTML.
  """
  html: String
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of salesforce-chat/docs/README.md from the salesforce-chat VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Salesforce chat
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

VTEX Salesforce chat first-party app

## How to install

Open the VTEX App Store and install this app on your store.

Now, open the app settings on your admin and fill in your Salesforce chat's Content.

## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/blaurenzano"><img src="https://avatars3.githubusercontent.com/u/49657838?v=4" width="100px;" alt=""/><br /><sub><b>blaurenzano</b></sub></a><br /><a href="https://github.com/vtex-apps/salesforce-chat/commits?author=blaurenzano" title="Code">💻</a></td>
  </tr>
</table>

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/service.json from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "stack": "nodejs",
  "memory": 258,
  "ttl": 43200,
  "timeout": 30,
  "minReplicas": 2,
  "maxReplicas": 30,
  "workers": 4,
  "cpu": 30,
  "routes": {
    "graphql": {
      "public": true,
      "path": "/graphql"
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/package.json from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "version": "1.0.1",
  "dependencies": {
    "@apollo/federation": "^0.18.1",
    "@graphql-tools/delegate": "^6.0.15",
    "@graphql-tools/merge": "^6.0.15",
    "@graphql-tools/wrap": "^6.0.15",
    "@types/co-body": "^5.1.0",
    "apollo-server-core": "^2.16.1",
    "axios": "^0.21.0",
    "cache-control-parser": "^1.0.7",
    "co-body": "^6.0.0",
    "eslint-config-vtex": "^12.8.8",
    "graphql": "^15.3.0",
    "isomorphic-unfetch": "^3.1.0"
  },
  "devDependencies": {
    "@vtex/api": "6.45.4",
    "typescript": "3.9.7",
    "vtex.checkout-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-graphql@0.55.1/public/@types/vtex.checkout-graphql",
    "vtex.graphql-gateway": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.graphql-gateway@0.7.0/public/_types/react",
    "vtex.search-resolver": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-resolver@1.29.4/public/_types/react"
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/global.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { IOClients, RecorderState, ServiceContext } from '@vtex/api'
import { ApolloServerHttpResponse } from 'apollo-server-core/dist/runHttpQuery'
import { GraphQLSchema } from 'graphql'

declare global {
  interface Query {
    operationName: string
    variables: Record<string, any> | string
    query: string
  }

  interface State extends RecorderState {
    query: Query
    schema: GraphQLSchema
    cacheControl: string[]
    responseInit: ApolloServerHttpResponse
  }

  type Context = ServiceContext<IOClients, State>
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/index.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import './global'

import { Cached, LRUCache, method, Service } from '@vtex/api'

import run from './middlewares/run'
import error from './middlewares/error'
import schema from './middlewares/schema'
import extract from './middlewares/extract'
import headers from './middlewares/headers'

const vbaseCacheStorage = new LRUCache<string, Cached>({
  max: 1e3,
})

metrics.trackCache('vbase', vbaseCacheStorage)

export default new Service({
  clients: {
    options: {
      vbase: {
        concurrency: 3,
        memoryCache: vbaseCacheStorage,
        retries: 1,
        timeout: 1500,
      },
    },
  },
  routes: {
    graphql: method({
      GET: [error, headers, extract, schema, run],
      POST: [error, headers, extract, schema, run],
    }),
  },
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/middlewares/schema.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { mergeSchemas } from '@graphql-tools/merge'
import {
  introspectSchema,
  RenameTypes,
  wrapSchema,
} from '@graphql-tools/wrap'
import { GraphQLSchema } from 'graphql'

import { NamespaceUnderFieldTransform } from '../transformers/namespaceUnderField'
import { executor as getExecutorForApp } from '../utils/executor'

let globalSchema: GraphQLSchema | null = null

const typeName = 'VTEX'
const fieldName = 'vtex'

const apps = [
  {
    app: 'vtex.search-resolver@1.x',
    executor: getExecutorForApp,
    transforms: [
      new RenameTypes(name => `${typeName}_${name}`),
      new NamespaceUnderFieldTransform(typeName, fieldName),
    ],
  },
  {
    app: 'vtex.checkout-graphql@0.x',
    executor: getExecutorForApp,
    transforms: [
      new RenameTypes(name => `${typeName}_${name}`),
      new NamespaceUnderFieldTransform(typeName, fieldName),
    ],
  }
]

export default async function schema(ctx: Context, next: () => Promise<void>) {
  if (!globalSchema) {
    const schemas = await Promise.all(
      apps.map(async ({ app, executor, transforms }) => {
        const exe = executor(app)

        return wrapSchema(
          {
            schema: await introspectSchema(exe, ctx),
            executor: exe,
          },
          transforms
        )
      })
    )

    globalSchema = mergeSchemas({ schemas })
  }

  ctx.state.schema = globalSchema

  await next()
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/middlewares/extract.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { VBase } from '@vtex/api'
import parse from 'co-body'
import fetch from 'isomorphic-unfetch'

interface PersistedQuery extends Query {
  extensions: {
    persistedQuery: {
      version: string
      sha256Hash: string
      storage: string
    }
  }
}

const BUCKET = 'persistedQueries'

const saveAsync = async (persisted: Record<string, string>, vbase: VBase) => {
  for (const hash of Object.keys(persisted)) {
    // eslint-disable-next-line no-await-in-loop
    await vbase.saveJSON(BUCKET, hash, persisted[hash]).catch(console.error)
  }
}

const isPersistedQuery = (query: any): query is PersistedQuery =>
  !!query.extensions

const parseString = (x: unknown) => {
  if (typeof x !== 'string') {
    return x
  }

  if (x === 'undefined') {
    return undefined
  }

  return JSON.parse(x)
}

export default async function extract(ctx: Context, next: () => Promise<void>) {
  const {
    vtex: { authToken, logger },
    clients: { vbase },
  } = ctx

  const rawQuery =
    ctx.request.method === 'POST' ? await parse.json(ctx) : ctx.request.query

  const query = {
    query: rawQuery.query,
    operationName: rawQuery.operationName,
    variables: parseString(rawQuery.variables),
    extensions: parseString(rawQuery.extensions),
  }

  // We have a persisted query in here. We need to translate it to a query
  // so graphql can understand and run it
  if (isPersistedQuery(query)) {
    const {
      extensions: {
        persistedQuery: { sha256Hash },
      },
    } = query

    const maybeQuery = await vbase.getJSON<string>(BUCKET, sha256Hash, true)

    // Query is already in our local storage. Just translate i
    if (maybeQuery) {
      query.query = maybeQuery
    }
    // Query is somewhere else. We need to fetch it and than try to translate it
    else {
      const storageHost = ctx.get('x-vtex-graphql-referer')
      const url = `http://${storageHost}/page-data/_graphql/persisted.graphql.json`

      // fetch persisted.json from remote
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'x-vtex-proxy-to': `https://${storageHost}`,
          accept: 'application/json; charset=utf-8',
          'Proxy-Authorization': authToken,
          'accept-encoding': 'gzip',
          // Cookie used to AB-test FastStore stores
          cookie: 'VtexStoreVersion=v2;',
        },
      })

      const responseText = await response.text()

      try {
        const persisted = JSON.parse(responseText)

        if (!persisted?.[sha256Hash]) {
          throw new Error(`URL ${url} does not contains hash ${sha256Hash}`)
        }

        // update local storage
        saveAsync(persisted, vbase).catch(console.error)

        // set query and continue
        query.query = persisted[sha256Hash]
      } catch (err) {
        logger.error({
          url,
          response: responseText.slice(0, 300),
          headers: response.headers,
        })
        throw err
      }
    }

    // Delete extensions so apollo does not try to parse the persisted query again
    delete query.extensions
  }

  ctx.state.query = query

  await next()
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/middlewares/headers.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import parse, { CacheControl } from 'cache-control-parser'

const ONE_WEEK_S = 3600 * 24 * 7
const BASE_CACHE_CONTROL = 'private, max-age=0, must-revalidate'

const format = (cacheControl: CacheControl) =>
  [
    cacheControl.isPrivate && 'private',
    cacheControl.isPublic && 'public',
    cacheControl.immutable && 'immutable',
    cacheControl.noCache && 'no-cache',
    cacheControl.noStore && 'no-store',
    cacheControl.mustRevalidate && 'must-revalidate',
    cacheControl.noTransform && 'no-transform',
    cacheControl.proxyRevalidate && 'proxy-revalidate',
    typeof cacheControl.staleIfError === 'number' &&
      `stale-if-error=${cacheControl.staleIfError}`,
    typeof cacheControl.staleWhileRevalidate === 'number' &&
      `stale-while-revalidate=${cacheControl.staleWhileRevalidate}`,
    typeof cacheControl.sharedMaxAge === 'number' &&
      `s-maxage=${cacheControl.sharedMaxAge}`,
    typeof cacheControl.maxAge === 'number' && `max-age=${cacheControl.maxAge}`,
  ]
    .filter(x => !!x)
    .join(', ')

export default async function headers(ctx: Context, next: () => Promise<void>) {
  ctx.state.cacheControl = []

  await next()

  const { headers: responseHeaders } = ctx.state.responseInit

  // Set Apollo computed Headers
  for (const [key, value] of Object.entries(responseHeaders ?? {})) {
    ctx.set(key, value)
  }

  // Set cache control.
  // Apollo cannot compute cache headers correctly, so we use the
  // returned headers from each stitched call to compute an aggregated
  // cache control header
  if (ctx.state.cacheControl.length === 0) {
    ctx.state.cacheControl.push(BASE_CACHE_CONTROL)
  }

  const cacheControl = ctx.state.cacheControl
    .map(parse)
    .reduce((previous, current) => {
      if (previous.noCache || previous.noStore || previous.isPrivate) {
        return previous
      }

      if (
        typeof current.maxAge === 'number' &&
        typeof previous.maxAge === 'number' &&
        current.maxAge > previous.maxAge
      ) {
        return previous
      }

      return current
    })

  if (cacheControl.isPublic && cacheControl.maxAge && cacheControl.maxAge > 0) {
    if (!cacheControl.staleWhileRevalidate) {
      cacheControl.staleWhileRevalidate = ONE_WEEK_S
    }

    if (!cacheControl.staleIfError) {
      cacheControl.staleIfError = ONE_WEEK_S
    }
  }

  ctx.set('cache-control', format(cacheControl))
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/middlewares/error.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
export default async function extract(ctx: Context, next: () => Promise<void>) {
  try {
    await next()
  } catch (err) {
    if (err.isGraphQLError) {
      ctx.body = err.message
      ctx.status = err.statusCode

      Object.entries(err.headers).forEach(([key, value]) => {
        ctx.set(key, value as any)
      })

      return
    }

    throw err
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/middlewares/run.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { LINKED, MAX_AGE } from '@vtex/api'
import { runHttpQuery } from 'apollo-server-core'

export default async function run(ctx: Context, next: () => Promise<void>) {
  const {
    state: { query, schema },
    request: { method },
    request,
  } = ctx

  const { graphqlResponse, responseInit } = await runHttpQuery([], {
    method,
    options: {
      cacheControl: {
        calculateHttpHeaders: true,
        defaultMaxAge: MAX_AGE.LONG,
      },
      context: ctx,
      debug: LINKED,
      schema,
      schemaHash: '' as any,
      tracing: false,
    },
    query,
    request,
  })

  ctx.body = graphqlResponse
  ctx.state.responseInit = responseInit

  await next()
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/utils/executor.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { AsyncExecutor } from '@graphql-tools/delegate'
import { parseAppId, versionToMajor } from '@vtex/api'
import http from 'axios'
import { print } from 'graphql'

export const executor = (
  app: string,
  axiosOptions?: (ctx: Context) => { headers: Record<string, string> }
): AsyncExecutor => async ({ document, variables, context }) => {
  const ctx = (context as unknown) as Context
  const {
    vtex: { account, workspace, authToken },
    state,
  } = ctx

  const { name, version } = parseAppId(app)
  const major = versionToMajor(version)
  const query = print(document)
  const data = JSON.stringify({ query, variables })

  const options = axiosOptions?.(ctx)

  const response = await http.request({
    method: 'POST',
    url: `http://app.io.vtex.com/${name}/v${major}/${account}/${workspace}/_v/graphql`,
    headers: {
      accept: 'application/json',
      'Content-Type': 'application/json',
      Authorization: authToken,
      'x-forwarded-host': (context as any).get('x-vtex-graphql-referer'),
      'x-vtex-locale': 'en-US',
      'x-vtex-tenant': 'en-US',
      ...options?.headers,
    },
    data,
  })

  const cacheControl = response.headers['cache-control']
  const setCookie = response.headers['set-cookie']

  if (setCookie) {
    ctx.set('set-cookie', setCookie)
  }

  if (cacheControl) {
    state.cacheControl.push(cacheControl)
  }

  return response.data
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of graphql-gateway/node/transformers/namespaceUnderField.ts from the graphql-gateway VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { GraphQLObjectType, GraphQLNonNull, GraphQLSchema } from 'graphql'
import { addTypes, modifyObjectFields } from '@graphql-tools/utils'

const EMTPY_OBJ = {}
const noop = () => EMTPY_OBJ

export class NamespaceUnderFieldTransform {
  constructor(protected typeName: string, protected fieldName: string) {}

  public transformSchema(schema: GraphQLSchema): GraphQLSchema {
    const queryType = schema.getQueryType()

    if (!queryType) {
      return schema
    }

    const queryConfig = queryType.toConfig()
    const nestedQuery = new GraphQLObjectType({
      ...queryConfig,
      name: this.typeName,
    })

    const newSchema = addTypes(schema, [nestedQuery])
    const newRootFieldConfigMap = {
      [this.fieldName]: {
        type: new GraphQLNonNull(nestedQuery),
        resolve: noop,
      },
    }

    const [transformedSchema] = modifyObjectFields(
      newSchema,
      queryConfig.name,
      () => true,
      newRootFieldConfigMap
    )

    return transformedSchema
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of giftcard-ui/node/service.json from the giftcard-ui VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "stack": "nodejs",
  "memory": 128,
  "routes": {
    "getgiftcards": {
      "path": "/_v/getgiftcards",
      "public": true
    },
    "postgiftcard": {
      "path": "/_v/postgiftcard",
      "public": true
    }
  },
  "events": {
    "onAppsLinked": {
      "sender": "apps",
      "keys": ["linked"]
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of giftcard-ui/node/typings.d.ts from the giftcard-ui VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'colossus' {
  import { Context as KoaContext } from 'koa'

  export interface IOContext {
    account: string
    workspace: string
    authToken: string
    params: {
      [param: string]: string
    }
    region: string
    route: string
  }

  export interface ColossusContext extends KoaContext {
    vtex: IOContext
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of giftcard-ui/node/package.json from the giftcard-ui VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.node-getting-started",
  "version": null,
  "dependencies": {
    "@vtex/api": "^0.37.1",
    "axios": "^0.18.0"
  },
  "devDependencies": {
    "@types/axios": "^0.14.0",
    "@types/koa": "^2.0.39",
    "@types/node": "8.x",
    "tslint": "^5.8.0",
    "tslint-config-vtex": "^2.0.0",
    "typescript": "^2.4.2"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'"
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of giftcard-ui/node/index.ts from the giftcard-ui VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ColossusContext } from 'colossus'
import { json } from 'co-body'
import axios from 'axios'

const appName = 'vtex-giftcard-v2'
const vendor = process.env.VTEX_APP_VENDOR
const workspace = process.env.VTEX_WORKSPACE
const region = process.env.VTEX_REGION

const urlBase = `http://${appName}.${vendor}.${region}.vtex.io/gatewayio/${workspace}/giftcardv2/gatewayio/giftcards`

function getCookieFrom(ctx) {
  const {
    request: {
      header: { cookie },
    },
    vtex: { authToken },
  } = ctx

  return {
    'Proxy-Authorization': authToken,
    'Content-Type': 'application/json',
    Cookie: cookie,
  }
}

export default {
  events: {
    onAppsLinked: async ctx => {
      console.log(`onAppsLinked body: ${ctx.body}`)
    },
  },
  routes: {
    getgiftcards: async (ctx: ColossusContext) => {
      ctx.set('Cache-Control', 'no-cache')

      const response = await axios(urlBase, {
        headers: getCookieFrom(ctx),
      })

      ctx.response.status = response.status
      ctx.response.body = response.data
    },
    postgiftcard: async (ctx: ColossusContext) => {
      const method = ctx.request.method
      if (method !== 'POST') {
        ctx.response.status = 405
        ctx.response.body = {
          message: 'Method not allowed',
        }
        return
      }

      ctx.set('Cache-Control', 'no-cache')

      const data = await json(ctx.req)
      const response = await axios({
        method: 'post',
        url: urlBase,
        data,
        headers: getCookieFrom(ctx),
      })

      ctx.response.status = response.status
      ctx.response.body = response.data
    },
    getgiftcard: async (ctx: ColossusContext) => {
      ctx.set('Cache-Control', 'no-cache')

      const id = ctx.query.giftCardId

      const response = await axios(`${urlBase}/${id}`, {
        headers: getCookieFrom(ctx),
      })

      ctx.response.status = response.status
      ctx.response.body = response.data
    },
  },
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of giftcard-ui/pages/pages.json from the giftcard-ui VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "pages": {
    "admin/giftcard": {
      "path": "/admin/giftcard"
    }
  },
  "extensions": {
    "admin/giftcard": {
      "component": "root"
    }
  }
}

```