[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 recommendation-shelf/examples/cart.js from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```javascript
const querySelector = '.checkout-container'
const workspaceCookie = 'VtexWorkspace'
const targetWorkspace = 'master'

function getCookie(name) {
  const regex = new RegExp(`(^|;)[ ]*${name}=([^;]*)`)
  const match = regex.exec(document.cookie)

  return match ? decodeURIComponent(match[2]) : null
}

function insertIframeAfterCheckoutContainer() {
  const container = document.querySelector(querySelector)

  if (!container) return

  const iframeContainer = document.createElement('div')

  iframeContainer.className = 'recommendations-embedded-shelf'
  iframeContainer.style.width = '100%'
  iframeContainer.style.height = '750px'
  iframeContainer.style.overflow = 'hidden'

  const iframe = document.createElement('iframe')
  // URL defined in the store-theme.
  const iframeUrl = '/_v/public/recommendations-embedded-shelf/'

  iframe.src = iframeUrl
  iframe.style.width = '100%'
  iframe.style.height = '100%'
  iframe.style.border = 'none'
  iframe.style.marginTop = '-125px'
  iframe.scrolling = 'no'
  iframe.id = 'recommendations-embedded-shelf-iframe'

  // Skip displaying the iframe if the current workspace is not the target workspace. Used for A/B testing

  // const currentWorkspace = getCookie(workspaceCookie)
  // if (currentWorkspace === null || (currentWorkspace && !currentWorkspace.includes(targetWorkspace))) return

  iframeContainer.appendChild(iframe)
  container.parentNode.insertBefore(iframeContainer, container.nextSibling)

  setInterval(() => {
    // Validates if the iframe is on the correct page
    if (
      !iframe.contentWindow.location.href.includes(iframeUrl) &&
      !iframe.contentWindow.location.pathname.endsWith('/p') // it should allow redirects to pdp
    ) {
      iframe.contentWindow.location.href =
        iframe.contentWindow.location.origin + iframeUrl
    }
  }, 1000)
  // Syncronize the iframe url with the parent window to allow some navigations...
  iframe.contentWindow.navigation.addEventListener(
    'navigate',
    function handleIframeNavigate(navigate) {
      if (!navigate.destination.url.includes(iframeUrl)) {
        window.location.href = navigate.destination.url
      }

      if (navigate.destination.url.includes('/checkout/#/cart')) {
        window.location.reload()
      }
    }
  )
}

function tryInsertIframe(retries = 100, interval = 75) {
  const container = document.querySelector(querySelector)

  if (container) {
    insertIframeAfterCheckoutContainer()
  } else if (retries > 0) {
    setTimeout(() => tryInsertIframe(retries - 1, interval), interval)
  }
}

window.addEventListener('load', () => tryInsertIframe())

```


[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 recommendation-shelf/react/RecommendationShelf.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages } from 'react-intl'

import { RecommendationShelfErrorBoundary } from './components/RecommendationShelfErrorBoundary'
import { RecommendationShelfContainer } from './components/RecommendationShelfContainer'

defineMessages({
  shelf: {
    id: 'admin/editor.recommendation-shelf',
    defaultMessage: 'Recommendation Shelf',
  },
  description: {
    id: 'admin/editor.recommendation-shelf.description',
    defaultMessage:
      'Recommendation Shelf is a component that displays a collection of items that are recommended to the user based on various algorithms and context data.',
  },
  title: {
    id: 'admin/editor.recommendation-shelf.title',
    defaultMessage: 'Shelf title',
  },
  campaignVrn: {
    id: 'admin/editor.recommendation-shelf.campaign-vrn',
    defaultMessage: 'Campaign VRN',
  },
  displayTitle: {
    id: 'admin/editor.recommendation-shelf.display-title',
    defaultMessage: 'Display Title',
  },
  itemsContext: {
    id: 'admin/editor.recommendation-shelf.items-context',
    defaultMessage: 'Items Context',
  },
  itemsContextDescription: {
    id: 'admin/editor.recommendation-shelf.items-context.description',
    defaultMessage:
      'From where to retrieve the items that will be used as context in the Recommendation request',
  },
  itemsContextCart: {
    id: 'admin/editor.recommendation-shelf.items-context.cart',
    defaultMessage: 'Cart',
  },
  itemsContextPdp: {
    id: 'admin/editor.recommendation-shelf.items-context.pdp',
    defaultMessage: 'Product Page',
  },
})

type Props = {
  campaignVrn: string
  title?: string
  displayTitle: boolean
  itemsContext: ItemContextType[]
}

const RecommendationShelf: StorefrontFunctionComponent<Props> = ({
  campaignVrn,
  title,
  displayTitle,
  itemsContext,
}) => {
  if (!campaignVrn) return null

  return (
    <RecommendationShelfErrorBoundary>
      <RecommendationShelfContainer
        campaignVrn={campaignVrn}
        title={title}
        displayTitle={displayTitle}
        itemsContext={itemsContext}
      />
    </RecommendationShelfErrorBoundary>
  )
}

RecommendationShelf.schema = {
  title: 'admin/editor.recommendation-shelf',
  description: 'admin/recommendation-shelf.description',
  type: 'object',
  properties: {
    title: {
      title: 'admin/editor.recommendation-shelf.title',
      type: 'string',
    },
    campaignVrn: {
      title: 'admin/editor.recommendation-shelf.campaign-vrn',
      type: 'string',
    },
    displayTitle: {
      title: 'admin/editor.recommendation-shelf.display-title',
      type: 'boolean',
      default: true,
    },
    itemsContext: {
      title: 'admin/editor.recommendation-shelf.items-context',
      description:
        'admin/editor.recommendation-shelf.items-context.description',
      type: 'array',
      items: {
        type: 'string',
        enum: ['PDP', 'CART'],
        enumNames: [
          'admin/editor.recommendation-shelf.items-context.pdp',
          'admin/editor.recommendation-shelf.items-context.cart',
        ],
      },
      default: ['PDP'],
    },
  },
}

export default RecommendationShelf

```


[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 recommendation-shelf/react/package.json from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "search-bar",
  "version": "2.14.2",
  "private": true,
  "dependencies": {
    "react": "^16.8.6",
    "react-apollo": "^3.1.5",
    "react-intl": "^3.12.0"
  },
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/graphql": "^14.5.0",
    "@types/node": "^14.18.0",
    "@vtex/test-tools": "^3.4.3",
    "@vtex/tsconfig": "^0.6.0",
    "braces": "^3.0.3",
    "form-data": "^2.5.4",
    "js-yaml": "^3.14.2",
    "micromatch": "^4.0.8",
    "node-notifier": "^8.0.1",
    "tough-cookie": "^4.1.3",
    "typescript": "3.9.7",
    "vtex.add-to-cart-button": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.add-to-cart-button@0.30.2/public/@types/vtex.add-to-cart-button",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.flex-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.flex-layout@0.21.4/public/@types/vtex.flex-layout",
    "vtex.order-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-manager@0.12.0/public/@types/vtex.order-manager",
    "vtex.product-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.10.1/public/@types/vtex.product-context",
    "vtex.product-price": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-price@1.31.2/public/@types/vtex.product-price",
    "vtex.product-summary": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-summary@2.90.4/public/@types/vtex.product-summary",
    "vtex.recommendation-bff": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.recommendation-bff@0.22.0/public/@types/vtex.recommendation-bff",
    "vtex.recommendation-shelf": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.recommendation-shelf@2.3.1/public/@types/vtex.recommendation-shelf",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.136.1/public/@types/vtex.render-runtime",
    "vtex.search-page-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-page-context@0.2.0/public/@types/vtex.search-page-context",
    "vtex.slider-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.slider-layout@0.24.7/public/@types/vtex.slider-layout"
  },
  "volta": {
    "node": "20.16.0",
    "yarn": "1.19.2"
  }
}

```


[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 recommendation-shelf/store/contentSchemas.json from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "RecommendationShelf": {
      "type": "object",
      "properties": {
        "title": {
          "title": "admin/editor.recommendation-shelf.title",
          "$ref": "app:vtex.native-types#/definitions/text"
        },
        "campaignVrn": {
          "title": "admin/editor.recommendation-shelf.campaign-vrn",
          "$ref": "app:vtex.native-types#/definitions/text"
        },
        "displayTitle": {
          "title": "admin/editor.recommendation-shelf.display-title",
          "type": "boolean",
          "default": true
        },
        "itemsContext": {
          "title": "admin/editor.recommendation-shelf.items-context",
          "type": "array",
          "default": ["PDP"],
          "items": {
            "title": "admin/editor.recommendation-shelf.items-context",
            "type": "string",
            "enum": ["PDP", "CART"],
            "enumNames": [
              "admin/editor.recommendation-shelf.items-context.pdp",
              "admin/editor.recommendation-shelf.items-context.cart"
            ]
          }
        }
      }
    }
  }
}

```


[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 recommendation-shelf/store/blocks.json from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "product-installments#summary": {
    "props": {
      "blockClass": "summary"
    }
  },
  "product-price-savings#summary": {
    "props": {
      "markers": ["discount"],
      "blockClass": "summary"
    }
  },
  "product-selling-price#summary": {
    "props": {
      "blockClass": "summary"
    }
  },
  "flex-layout.row#selling-price-savings": {
    "props": {
      "colGap": 2,
      "preserveLayoutOnMobile": true,
      "preventHorizontalStretch": true,
      "marginBottom": 4
    },
    "children": [
      "product-selling-price#summary",
      "product-price-savings#summary"
    ]
  },
  "product-list-price#summary": {
    "props": {
      "blockClass": "summary"
    }
  },
  "product-summary-image#shelf": {
    "props": {
      "showBadge": false,
      "aspectRatio": "1:1",
      "maxHeight": 300
    }
  },
  "product-summary.shelf": {
    "children": [
      "product-summary-image#shelf",
      "product-summary-name",
      "product-summary-space",
      "product-list-price#summary",
      "flex-layout.row#selling-price-savings",
      "product-installments#summary",
      "add-to-cart-button"
    ]
  },
  "slider-layout#shelf": {
    "props": {
      "itemsPerPage": {
        "desktop": 5,
        "tablet": 3,
        "phone": 1
      },
      "infinite": true,
      "fullWidth": false,
      "blockClass": "shelf"
    }
  },
  "list-context.product-list-static": {
    "blocks": ["product-summary.shelf"],
    "children": ["slider-layout#shelf"]
  },
  "recommendation-shelf": {
    "blocks": ["list-context.product-list-static"]
  }
}

```


[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 recommendation-shelf/store/interfaces.json from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "recommendation-shelf": {
    "component": "RecommendationShelf",
    "required": ["list-context.product-list-static"],
    "content": {
      "$ref": "#/definitions/RecommendationShelf"
    }
  }
}

```


[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 recommendation-shelf/react/typings/vtex.search-page-context.d.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.search-page-context/SearchPageContext' {
  export const useSearchPage
}

```


[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 recommendation-shelf/react/typings/vtex.order-manager.d.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.order-manager/OrderForm' {
  export * from 'vtex.order-manager/react/OrderForm'
  export { default } from 'vtex.order-manager/react/OrderForm'
}

```


[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 recommendation-shelf/react/typings/global.d.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { FunctionComponent } from 'react'

declare global {
  /* eslint-disable @typescript-eslint/ban-types */
  interface StorefrontFunctionComponent<P = {}> extends FunctionComponent<P> {
    schema?: object
    getSchema?(props?: P): object
  }

  interface Window {
    __RUNTIME__?: {
      account?: string
      // add other properties if needed
    }
  }

  export type RecommendationType =
    | 'CROSS_SELL'
    | 'SIMILAR_ITEMS'
    | 'PERSONALIZED'
    | 'TOP_ITEMS'
    | 'LAST_SEEN'
    | 'VISUAL_SIMILARITY'
    | 'SEARCH_BASED'

  export type ItemContextType = 'PDP' | 'CART'
}

```


[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 recommendation-shelf/react/typings/css.d.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  const styles: {
    [key: string]: string
  }

  export default styles
}

```


[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 recommendation-shelf/react/typings/recommend-bff.d.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'recommend-bff' {
  export type Product = {
    productId: string
    items: Array<{
      itemId: string
    }>
  }

  export type RecommendationsV2RequestQuery = {
    an: string
    userId: string
    campaignVrn: string
    products?: string
  }

  export type RecommendationsV2Response = {
    products: Product[]
    correlationId: string
    campaign: {
      id: string
      title?: string
      type: RecommendationType
    }
  }
}

```


[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 recommendation-shelf/react/utils/requests.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
export function generateRecOriginHeader(account: string) {
  return {
    'x-vtex-rec-origin': `${account}/storefront/vtex.recommendation-shelf@2.x`,
  }
}

```


[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 recommendation-shelf/react/utils/vrn.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable padding-line-between-statements */

type RecommendationVrnType =
  | 'rec-cross-v1'
  | 'rec-similar-v1'
  | 'rec-persona-v1'
  | 'rec-last-v1'
  | 'rec-top-items-v1'
  | 'rec-cross-v2'
  | 'rec-similar-v2'
  | 'rec-persona-v2'
  | 'rec-last-v2'
  | 'rec-top-items-v2'
  | 'rec-search-v2'

const vrnPattern =
  /^vrn:recommendations:[^:]+:(rec-cross-v1|rec-similar-v1|rec-persona-v1|rec-last-v1|rec-top-items-v1|rec-cross-v2|rec-similar-v2|rec-persona-v2|rec-last-v2|rec-top-items-v2|rec-search-v2):[^:]+$/

export function isValidVrn(campaignVrn: string): boolean {
  return vrnPattern.test(campaignVrn)
}

function parseCampaignVrn(campaignVrn: string) {
  const [_, __, accountName, campaignType, campaignId] = campaignVrn.split(':')

  return {
    accountName,
    campaignId,
    campaignVrnType: campaignType as RecommendationVrnType,
  }
}

// Cross-sell: rec-cross-v1,  rec-cross-v2
// Similar-items: rec-similar-v1, rec-similar-v2
// Cart Recommmendations: rec-cart-v1, rec-cart-v2
// Personalized: rec-persona-v1, rec-persona-v2
// Last Seen: rec-last-v1, rec-last-v2
// Top items: rec-top-items-v1, rec-top-items-v2
// Recent interactions: rec-recent-int-v1, rec-recent-int-v2
export function getTypeFromVrn(campaignVrn: string): RecommendationType {
  const { campaignVrnType } = parseCampaignVrn(campaignVrn)

  switch (campaignVrnType) {
    case 'rec-cross-v1':
    case 'rec-cross-v2':
      return 'CROSS_SELL'

    case 'rec-similar-v1':
    case 'rec-similar-v2':
      return 'SIMILAR_ITEMS'

    case 'rec-persona-v1':
    case 'rec-persona-v2':
      return 'PERSONALIZED'

    case 'rec-last-v1':
    case 'rec-last-v2':
      return 'LAST_SEEN'

    case 'rec-top-items-v1':
    case 'rec-top-items-v2':
      return 'TOP_ITEMS'

    case 'rec-search-v2':
      return 'SEARCH_BASED'

    default:
      throw new Error(`Unknown campaign type: ${campaignVrnType}`)
  }
}

```


[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 recommendation-shelf/react/utils/logger.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { generateRecOriginHeader } from './requests'

type LogLevel = 'info' | 'warn' | 'error' | 'debug'

type LoggerOptions = {
  message: string
  data?: Record<
    string,
    number | string | boolean | undefined | null | object[] | Error
  > // Changed to Record for better type safety
  sendLog?: boolean
}

function getAccount() {
  return window.__RUNTIME__?.account
}

class Logger {
  private prefix: string

  constructor() {
    this.prefix = '[vtex.recommendation-shelf@2.x]'
  }

  public log(level: LogLevel, args: LoggerOptions) {
    const message = `${this.prefix} ${args.message}`
    /* eslint-disable padding-line-between-statements */
    switch (level) {
      case 'info':
        console.info(message, args.data)
        break
      case 'warn':
        console.warn(message, args.data)
        break
      case 'error':
        console.error(message, args.data)
        break
      default:
        // eslint-disable-next-line no-console
        console.log(message, args.data)
    }

    // Send log to service if sendLog is true
    if (args.sendLog) {
      this.sendLogToService(level, args)
    }
  }

  private async sendLogToService(level: LogLevel, args: LoggerOptions) {
    const account = getAccount()
    if (!account) {
      console.warn('No account found, skipping log sending')
      return
    }

    try {
      await fetch(`/api/recommend-bff/logs?an=${account}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...generateRecOriginHeader(account),
        },
        body: JSON.stringify({
          app: 'vtex.recommendation-shelf',
          message: args.message,
          level,
          url: window.document.URL,
          ...args.data,
        }),
      })
    } catch (error) {
      // Silent fail to avoid logging loops
      console.error(
        `${this.prefix} Failed to send log to service: (${args.message})`,
        error
      )
    }
  }

  public info(args: LoggerOptions) {
    this.log('info', args)
  }

  public warn(args: LoggerOptions) {
    this.log('warn', args)
  }

  public error(args: LoggerOptions) {
    this.log('error', args)
  }

  public debug(args: LoggerOptions) {
    this.log('debug', args)
  }
}

export const logger = new Logger()

```


[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 recommendation-shelf/react/utils/getWithRetry.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
export function getWithRetry<T>(
  getFn: () => T,
  retries = 30,
  delay = 200
): Promise<T> {
  return new Promise((resolve, reject) => {
    function attempt(n: number) {
      try {
        const result = getFn()

        if (!result) {
          throw new Error('Result is undefined or null')
        }

        resolve(result)
      } catch (error) {
        if (n <= 1) {
          reject(error)
        } else {
          setTimeout(() => attempt(n - 1), delay + (retries - n) * delay)
        }
      }
    }

    attempt(retries)
  })
}

```


[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 recommendation-shelf/react/utils/attachViewEvent.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable padding-line-between-statements */

/**
 * IMPORTANT
 *
 * The following logic was extracted from "https://github.com/vtex/analytics-activity-flow-script/blob/4694e60b36ef15f852a16d87abb5270dc62f71c3/scripts/web/src/ads/utils/attachViewEvent.ts"
 * We just copied the code here since we don't have a straight forward way to re-use it in both places. In the future this will be removed when we consolidate all the analytics logic to be done via activity-flow.
 *
 */

/**
 * Possible view status of an element.
 */
type ViewStatus = 'NOT_VIEWED' | 'IN_VIEW' | 'VIEWED'

/**
 * A map of unique elements that have been tracked either in or views.
 */
type TrackedViewStatus = Record<string, ViewStatus>

/**
 * A map of the timeout functions by unique ID. It's done to prevent
 * multiple timeout running at once.
 */
type TimeoutFunctions = Record<string, ReturnType<typeof setTimeout>>

/**
 * Arguments passed to the onIntersectionChange function.
 */
type OnIntersectionChangeArgs = {
  entry: IntersectionObserverEntry
  id: string
  element: Element
  observer: IntersectionObserver
}

/**
 * The minimum time an ad must be visible to be considered viewed.
 * This is the IAB standard.
 */
export const MINIMUM_VIEW_TIME = 1000 // 1 second

let trackedViewStatus: TrackedViewStatus = {}
let timeoutFunctions: TimeoutFunctions = {}

/**
 * Clear the tracked elements view statuses.
 */
export function clearTrackedViews() {
  trackedViewStatus = {}
  timeoutFunctions = {}
}

/**
 * Attach a custom "view" event to an element. The event will be dispatched
 * when the element is at least 50% visible for at least 1 second. It will
 * only be dispatched once.
 * @param element The HTML element to be tracked.
 * @param id A unique ID for the element
 */
export function attachViewEvent(element: Element, id: string) {
  if (getViewStatus(id) === 'VIEWED') return

  const options = { threshold: 0.5, rootMargin: '0px' }

  const observer = new window.IntersectionObserver((entries) => {
    entries.forEach((entry) =>
      onIntersectionChange({ id, observer, element, entry })
    )
  }, options)

  observer.observe(element)
}

/**
 * Called everytime the element appaers or disappears from the viewport.
 */
function onIntersectionChange({
  id,
  element,
  observer,
  entry,
}: OnIntersectionChangeArgs) {
  const viewStatus = getViewStatus(id)

  // eslint-disable-next-line default-case
  switch (viewStatus) {
    case 'NOT_VIEWED':
      if (!entry.isIntersecting) break

      setViewStatus(id, 'IN_VIEW')

      waitAndCallbackIfElementIsInView(id, () => {
        setViewStatus(id, 'VIEWED')
        observer.disconnect()

        dispatchViewEvent(element)
      })

      break
    case 'IN_VIEW':
      if (!entry.isIntersecting) setViewStatus(id, 'NOT_VIEWED')

      break
    case 'VIEWED':
      observer.disconnect()
      break
  }
}

/**
 * Call a callback if the element is still in view after the minimum view time.
 */
function waitAndCallbackIfElementIsInView(id: string, callback: () => void) {
  clearTimeoutFunction(id)

  const timeout = setTimeout(() => {
    if (getViewStatus(id) !== 'IN_VIEW') return

    callback()
  }, MINIMUM_VIEW_TIME)

  setTimeoutFunction(id, timeout)
}

/**
 * Dispatch a custom JS view event on the element.
 */
function dispatchViewEvent(element: Element) {
  element.dispatchEvent(new Event('view'))
}

/**
 * Set the view status of an element.
 */
function setViewStatus(id: string, status: ViewStatus) {
  trackedViewStatus[id] = status
}

/**
 * Get the view status of an element.
 */
function getViewStatus(id: string) {
  return trackedViewStatus[id] ?? 'NOT_VIEWED'
}

/**
 * Clear a timeout function if it exists to prevent multiple timeouts.
 */
function clearTimeoutFunction(id: string) {
  const timeout = timeoutFunctions[id]

  if (timeout) clearTimeout(timeout)
}

/**
 * Store the timeout function by ID.
 */
function setTimeoutFunction(
  id: string,
  timeout: ReturnType<typeof setTimeout>
) {
  timeoutFunctions[id] = timeout
}

```


[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 recommendation-shelf/react/utils/user.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { getWithRetry } from './getWithRetry'

function getCookie(name: string): string | null {
  const regex = new RegExp(`(^|;)[ ]*${name}=([^;]*)`)
  const match = regex.exec(document.cookie)

  return match ? decodeURIComponent(match[2]) : null
}

async function getCookieExpiration(name: string): Promise<string | null> {
  // Try to use Cookie Store API if available (modern browsers)
  if ('cookieStore' in window) {
    try {
      const { cookieStore } = window as Window & {
        cookieStore?: {
          get: (name: string) => Promise<{
            expires?: Date | number
            [key: string]: unknown
          } | null>
        }
      }

      if (cookieStore) {
        const cookie = (await cookieStore.get(name)) as {
          expires?: Date | number
        } | null

        if (cookie?.expires) {
          // Cookie Store API returns expiration as a Date object or timestamp
          if (cookie.expires instanceof Date) {
            return cookie.expires.toUTCString()
          }

          if (typeof cookie.expires === 'number') {
            return new Date(cookie.expires).toUTCString()
          }
        }
      }
    } catch {
      // Cookie Store API not available or failed, fall through to fallback
    }
  }

  // Fallback: document.cookie doesn't include expiration info,
  // so we return null and will use a default expiration
  return null
}

function setCookie(
  name: string,
  value: string,
  expirationDate?: string | Date
): void {
  let expires = ''

  if (expirationDate) {
    if (typeof expirationDate === 'string') {
      expires = `expires=${expirationDate};`
    } else {
      expires = `expires=${expirationDate.toUTCString()};`
    }
  } else {
    // Default to 1 days if no expiration provided
    const date = new Date()

    date.setTime(date.getTime() + 1 * 24 * 60 * 60 * 1000)
    expires = `expires=${date.toUTCString()};`
  }

  document.cookie = `${name}=${encodeURIComponent(value)};${expires}path=/`
}

export function getUserIdFromCookie(): string {
  const recommendationUser = getCookie('vtex-rec-user-id')
  const syneryUser = getCookie('_snrs_uuid')

  return recommendationUser ?? syneryUser ?? ''
}

type CookieState = {
  snrsUuid: string | null
  vtexRecUserId: string | null
  vtexRCMacId: string | null
}

/**
 * Ensures that userId cookies (_snrs_uuid or vtex-rec-user-id) exist.
 * If they don't exist, creates them using the value from VtexRCMacIdv7 cookie.
 * This function should be called whenever a RecommendationShelf is rendered.
 */
export async function ensureUserIdCookies(): Promise<void> {
  if (typeof document === 'undefined') {
    return
  }

  // Check all cookies with retry to ensure we have the latest state

  let cookieState: CookieState

  try {
    cookieState = await getWithRetry<CookieState>(
      () => {
        const snrsUuid = getCookie('_snrs_uuid')
        const vtexRecUserId = getCookie('vtex-rec-user-id')
        const vtexRCMacId = getCookie('VtexRCMacIdv7')

        // Return state if we have userId cookies OR if we have VtexRCMacIdv7
        // This ensures we proceed if either condition is met
        if (snrsUuid || vtexRecUserId || vtexRCMacId) {
          return {
            snrsUuid,
            vtexRecUserId,
            vtexRCMacId,
          }
        }

        // Throw to trigger retry if nothing is available
        throw new Error('No cookies available')
      },
      15,
      200
    )
  } catch (error) {
    return
  }

  // If userId cookies already exist, do nothing
  if (cookieState.snrsUuid || cookieState.vtexRecUserId) {
    return
  }

  // If VtexRCMacIdv7 doesn't exist, do nothing
  if (!cookieState.vtexRCMacId) {
    return
  }

  // Get the expiration from VtexRCMacIdv7 cookie
  const expiration = await getCookieExpiration('VtexRCMacIdv7')

  // Create both cookies with the value and expiration from VtexRCMacIdv7
  setCookie('_snrs_uuid', cookieState.vtexRCMacId, expiration ?? undefined)
  setCookie(
    'vtex-rec-user-id',
    cookieState.vtexRCMacId,
    expiration ?? undefined
  )
}

```


[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 recommendation-shelf/react/components/RecommendationShelfErrorBoundary.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component, Fragment } from 'react'

import { logger } from '../utils/logger'

export class RecommendationShelfErrorBoundary extends Component<
  any,
  { hasError: boolean }
> {
  constructor(props: any) {
    super(props)
    this.state = { hasError: false }
  }

  public static getDerivedStateFromError() {
    return { hasError: true }
  }

  public componentDidCatch(error: Error) {
    logger.error({
      message: 'Error while rendering RecommendationShelf',
      data: { error },
      sendLog: true,
    })
  }

  public render() {
    if (this.state.hasError) {
      return <Fragment />
    }

    return this.props.children
  }
}

```


[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 recommendation-shelf/react/components/RecommendationShelfContainer.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Fragment, useEffect, useMemo, useState } from 'react'
import { useProduct } from 'vtex.product-context'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import { canUseDOM } from 'vtex.render-runtime'

import useRecommendations from '../hooks/useRecommendations'
import Shelf from './Shelf'
import { getTypeFromVrn, isValidVrn } from '../utils/vrn'
import { getUserIdFromCookie, ensureUserIdCookies } from '../utils/user'
import { getWithRetry } from '../utils/getWithRetry'
import { logger } from '../utils/logger'
import { ShelfSkeleton } from './ShelfSkeleton'

type Props = {
  campaignVrn: string
  title?: string
  displayTitle: boolean
  itemsContext: ItemContextType[]
}

export const RecommendationShelfContainer: React.FC<Props> = ({
  campaignVrn,
  title,
  displayTitle,
  itemsContext = ['PDP'],
}) => {
  const productContext = useProduct()
  const {
    orderForm: { items: orderFormItems },
  } = useOrderForm()

  const [userId, setUserId] = useState<string | null | undefined>(undefined)

  const campaignType = getTypeFromVrn(campaignVrn)
  // Ensure userId cookies exist when component mounts

  useEffect(() => {
    if (canUseDOM) {
      ensureUserIdCookies().catch((error) => {
        console.error(
          '[vtex.recommendation-shelf@2.x] Error ensuring userId cookies',
          error
        )
      })
    }
  }, [])

  const cartItems: string[] =
    orderFormItems?.map((item: { productId: string }) => item.productId) ?? []

  const currentProduct = productContext?.product?.productId

  // Compose product IDs based on itemsContext
  let productsIds: string[] = []

  if (itemsContext.includes('PDP') && currentProduct) {
    productsIds.push(currentProduct)
  }

  if (itemsContext.includes('CART')) {
    productsIds = productsIds.concat(cartItems)
  }

  // Remove duplicates and falsy values
  productsIds = Array.from(new Set(productsIds)).filter(Boolean)

  if (canUseDOM && !userId && userId !== null) {
    // The pixel might take a while to load and set the userId cookie,
    // so we use a retry mechanism to ensure we get the userId if available.
    getWithRetry<string>(() => {
      if (canUseDOM && !userId) {
        return getUserIdFromCookie()
      }

      return ''
    })
      .then((value) => {
        setUserId(value)
      })
      .catch((error) => {
        logger.error({
          message: 'Error retrieving userId from cookie',
          data: { error, campaignType },
          sendLog: true,
        })
        setUserId(null)
      })
  }

  const { data, error, loading } = useRecommendations({
    userId,
    campaignVrn,
    products: productsIds,
  })

  const products = useMemo(() => {
    if (error || !data) {
      return undefined
    }

    const recommended = data.products

    if (recommended && recommended.length > 0) {
      return recommended
    }

    return undefined
  }, [data, error])

  if (loading || userId === undefined) {
    return <ShelfSkeleton />
  }

  if (campaignVrn && !isValidVrn(campaignVrn)) {
    logger.warn({
      message: 'Shelf not displayed due to invalid campaignVrn',
      data: { campaignVrn, campaignType },
    })
  }

  if ((products && products.length === 0 && loading === false) || error) {
    logger.warn({
      message: 'Shelf not displayed due to missing products or an error',
      data: { products, campaignVrn, error },
    })
  }

  return products?.length && userId ? (
    <Shelf
      products={products}
      title={title ?? data?.campaign.title ?? ''}
      correlationId={data?.correlationId ?? ''}
      userId={userId}
      displayTitle={displayTitle}
      campaignId={data?.campaign.id ?? ''}
    />
  ) : (
    <Fragment />
  )
}

```


[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 recommendation-shelf/react/hooks/useRecommendations.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useEffect, useState } from 'react'
import { canUseDOM, useRuntime } from 'vtex.render-runtime'
import type {
  RecommendationsV2RequestQuery as Args,
  RecommendationsV2Response as Response,
} from 'recommend-bff'

import { generateRecOriginHeader } from '../utils/requests'
import { getTypeFromVrn } from '../utils/vrn'

type RecommendationInput = {
  campaignVrn: string
  products: string[]
  userId?: string | null
}

function getRecommendationArguments(
  input: RecommendationInput,
  account: string
): Args | null {
  const { userId, products, campaignVrn } = input

  const recommendationType = getTypeFromVrn(campaignVrn)

  if (!userId) {
    return null
  }

  let args: Args = {
    an: account,
    campaignVrn,
    userId,
  }

  /* eslint-disable padding-line-between-statements */
  switch (recommendationType) {
    case 'VISUAL_SIMILARITY':
    case 'SIMILAR_ITEMS':
      if (products.length === 0) {
        return null
      }
      args = {
        ...args,
        an: account,
        products: products[0],
      }

      break
    case 'CROSS_SELL':
      if (products.length === 0) {
        return null
      }
      args = {
        ...args,
        an: account,
        products: products.join(';'),
      }
      break
    default:
      break
  }

  return args
}

function useRecommendations(args: RecommendationInput) {
  const runtime = useRuntime()
  const { account } = runtime

  const variables = getRecommendationArguments(args, account)
  const shouldSkip = !canUseDOM || !variables
  const userId = variables?.userId
  const products = variables?.products
  const campaignVrn = variables?.campaignVrn

  const [data, setData] = useState<Response | null>(null)
  const [error, setError] = useState<Error | null>(null)
  const [loading, setLoading] = useState<boolean>(false)

  useEffect(() => {
    if (shouldSkip) return

    setLoading(true)
    setError(null)

    const params: Record<string, string> = {
      an: account,
    }
    if (userId) params.userId = userId
    if (products) params.products = products
    if (campaignVrn) params.campaignVrn = campaignVrn

    const queryParams = new URLSearchParams(params).toString()

    fetch(`/api/recommend-bff/v2/recommendations?${queryParams}`, {
      method: 'GET',
      headers: {
        ...generateRecOriginHeader(account),
      },
    })
      .then(async (response) => {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`)
        }
        const result = await response.json()
        setData(result)
      })
      .catch((err) => {
        setError(err)
        setData(null)
      })
      .finally(() => {
        setLoading(false)
      })
  }, [account, shouldSkip, userId, products, campaignVrn])

  return {
    error,
    data,
    loading,
  }
}

export default useRecommendations

```


[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 recommendation-shelf/react/components/ShelfSkeleton/index.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles } from 'vtex.css-handles'

import { SkeletonPiece } from './SkeletonPiece'

const CSS_HANDLES = ['recommendationShelfContainer']

function checkDevice(): 'DESKTOP' | 'MOBILE' | 'TABLET' {
  if (typeof window === 'undefined') {
    return 'MOBILE'
  }

  if (window.innerWidth <= 768) {
    return 'MOBILE'
  }

  if (window.innerWidth <= 1024) {
    return 'TABLET'
  }

  if (window.innerWidth > 1024) {
    return 'DESKTOP'
  }

  return 'MOBILE'
}

const DEVICE_MAP = {
  DESKTOP: 5,
  MOBILE: 2,
  TABLET: 3,
}

export function ShelfSkeleton() {
  const handles = useCssHandles(CSS_HANDLES)
  const device = checkDevice()
  const skeletonCount = DEVICE_MAP[device] || DEVICE_MAP.DESKTOP
  const skeletonPieces = Array.from({ length: skeletonCount }, (_, index) => (
    <SkeletonPiece key={index} />
  ))

  return (
    <div
      className={`${handles.recommendationShelfContainer} w-100 flex justify-center`}
    >
      {skeletonPieces}
    </div>
  )
}

```


[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 recommendation-shelf/react/components/ShelfSkeleton/SkeletonPiece.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import './style.css'

import React from 'react'
import { useCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = [
  'recommendationSkeletonPiece',
  'recommendationSkeletonPieceShimmer',
]

export function SkeletonPiece() {
  const handles = useCssHandles(CSS_HANDLES)

  return (
    <div
      className={`${handles.recommendationSkeletonPiece} bg-muted-4 br3 center`}
    >
      <div className={`${handles.recommendationSkeletonPieceShimmer}`} />
    </div>
  )
}

```


[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 recommendation-shelf/react/components/ShelfSkeleton/style.css from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```css
/* Skeleton animation */
@keyframes shimmer-anim {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(50%, 0, 0);
  }
}

.recommendationSkeletonPiece {
  height: 550px;
  width: 300px;
}

.recommendationSkeletonPieceShimmer {
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 0.30),
    rgba(255, 255, 255, 0)
  );
  background-size: 50% 100%;
  animation: shimmer-anim 1s linear infinite;
}

.recommendationShelfContainer {
  gap: 1.5rem;
}

```


[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 recommendation-shelf/react/components/Shelf/index.tsx from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useRef, useCallback } from 'react'
import { ExtensionPoint, useRuntime } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'
import type { Product } from 'recommend-bff'

import styles from './styles.css'
import { notifyClick } from './notifyClick'
import { notifyView } from './notifyView'
import { attachViewEvent } from '../../utils/attachViewEvent'

type Props = {
  userId: string
  correlationId: string
  products: Product[]
  displayTitle: boolean
  title?: string
  campaignId: string
}

const CSS_HANDLES = [
  'recommendationShelfContainer',
  'shelfTitleContainer',
  'shelfTitle',
]

const Shelf: StorefrontFunctionComponent<Props> = ({
  title,
  products,
  correlationId,
  userId,
  displayTitle,
  campaignId,
}) => {
  const shelfDivRef = useRef<HTMLDivElement>(null)
  const handles = useCssHandles(CSS_HANDLES)
  const { account } = useRuntime()

  const onProductClick = useCallback(
    (p: Product) => {
      const itemId = p.productId ?? ''

      notifyClick({
        productId: itemId,
        correlationId,
        userId,
        account,
        campaignId,
      })
    },
    [correlationId, userId, account, campaignId]
  )

  const onView = useCallback(() => {
    notifyView({
      userId,
      correlationId,
      products: products.map((p) => p.productId ?? ''),
      account,
      campaignId,
    })
  }, [products, userId, correlationId, account, campaignId])

  useEffect(() => {
    const currentShelfDiv = shelfDivRef.current

    if (!currentShelfDiv) return

    attachViewEvent(currentShelfDiv, `${correlationId}`)
    currentShelfDiv.addEventListener('view', onView)

    return () => {
      // Remove listener on unmount to avoid multiple calls
      currentShelfDiv.removeEventListener('view', onView)
    }
  }, [shelfDivRef, products, userId, correlationId, onView])

  return (
    <div
      className={`${handles.recommendationShelfContainer}`}
      ref={shelfDivRef}
    >
      {title && displayTitle && (
        <div className={`mv4 tc v-mid ${handles.shelfTitleContainer}`}>
          <span className={`${styles.shelfTitle} ${handles.shelfTitle}`}>
            {title}
          </span>
        </div>
      )}
      <ExtensionPoint
        id="list-context.product-list-static"
        products={products}
        actionOnProductClick={onProductClick}
      />
    </div>
  )
}

export default Shelf

```


[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 recommendation-shelf/react/components/Shelf/styles.css from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```css
.shelfTitle {
  font-weight: 600;
  font-size: 1.25rem;
}

```


[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 recommendation-shelf/react/components/Shelf/notifyClick.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { generateRecOriginHeader } from '../../utils/requests'
import { logger } from '../../utils/logger'

type NotifyParams = {
  account: string
  correlationId: string
  productId: string
  userId: string
  campaignId: string
}

export async function notifyClick(params: NotifyParams) {
  const path = `/api/recommend-bff/v2/events/recommendation-click?an=${params.account}`

  try {
    await fetch(path, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...generateRecOriginHeader(params.account),
      },
      body: JSON.stringify({
        userId: params.userId,
        correlationId: params.correlationId,
        product: params.productId,
        campaignId: params.campaignId,
      }),
    })
  } catch (err) {
    logger.error({
      message: 'Error while notifying campaign click',
      data: 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 recommendation-shelf/react/components/Shelf/notifyView.ts from the recommendation-shelf VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { generateRecOriginHeader } from '../../utils/requests'
import { logger } from '../../utils/logger'

type NotifyView = {
  account: string
  correlationId: string
  products: string[]
  userId: string
  campaignId: string
}

export async function notifyView(params: NotifyView) {
  const path = `/api/recommend-bff/v2/events/recommendation-view?an=${params.account}`

  try {
    await fetch(path, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...generateRecOriginHeader(params.account),
      },
      body: JSON.stringify({
        userId: params.userId,
        correlationId: params.correlationId,
        products: params.products,
        campaignId: params.campaignId,
      }),
    })
  } catch (err) {
    logger.error({
      message: 'Error while notifying recommendation view',
      data: 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 tax-fallback/docs/README.md from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Tax Fallback API

This app's API provides tax tables that can be used for simple tax calculation when a dynamic tax calculation is not available. New tax tables are downloaded every 4 weeks.

You do not need to install this app in your account. It is installed in the `vtexus` account and other apps can send requests to its API there.

To retrieve taxes for a given postal code, your app can send a GET request to the following URL:

### https://vtexus.myvtex.com/_v/tax-fallback/{country}/{provider}/{postalCode}

| URL Param    |   Type   |            Description             |   Supported Values   |
| ------------ | :------: | :--------------------------------: | :------------------: |
| `country`    | `string` |     Destination country (ISO2)     |         `us`         |
| `provider`   | `string` |         Tax table provider         |      `avalara`       |
| `postalCode` | `string` | Destination postal code (5 digits) | (any US postal code) |

Example request:

`GET https://vtexus.myvtex.com/_v/tax-fallback/us/avalara/14617`

Example response:

```json
{
  "id": "13a3e885-1496-11eb-8374-12b3893429c7",
  "date": "2020-10-26",
  "ZIP_CODE": "14617",
  "STATE_ABBREV": "NY",
  "COUNTY_NAME": "MONROE",
  "CITY_NAME": "ROCHESTER",
  "STATE_SALES_TAX": 0.04,
  "STATE_USE_TAX": 0.04,
  "COUNTY_SALES_TAX": 0.04,
  "COUNTY_USE_TAX": 0.04,
  "CITY_SALES_TAX": 0,
  "CITY_USE_TAX": 0,
  "TOTAL_SALES_TAX": 0.08,
  "TOTAL_USE_TAX": 0.08,
  "TAX_SHIPPING_ALONE": true,
  "TAX_SHIPPING_AND_HANDLING_TOGETHER": true
}
```

```


[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 tax-fallback/node/service.json from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 512,
  "ttl": 60,
  "timeout": 30,
  "minReplicas": 2,
  "maxReplicas": 10,
  "workers": 1,
  "routes": {
    "getFallbackTaxes": {
      "path": "/_v/tax-fallback/:country/:provider/:postalCode",
      "public": true
    },
    "downloadFallbackTaxes": {
      "path": "/_v/download-taxes/:country/:provider",
      "public": false
    }
  },
  "events": {
    "taxUpdate": {
      "sender": "vtex.tax-fallback",
      "keys": ["taxFallback.taxUpdate"]
    }
  }
}

```


[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 tax-fallback/node/package.json from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "co-body": "^6.0.0",
    "csv-parse": "^4.12.0",
    "ramda": "^0.25.0",
    "tiny-async-pool": "^1.1.0"
  },
  "devDependencies": {
    "@types/co-body": "^0.0.3",
    "@types/csv-parse": "^1.2.2",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.0.0",
    "@types/ramda": "types/npm-ramda#dist",
    "@types/tiny-async-pool": "^1.0.0",
    "@vtex/api": "6.45.12",
    "@vtex/test-tools": "^1.0.0",
    "typescript": "3.9.7"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty"
  },
  "version": "0.1.0"
}

```


[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 tax-fallback/node/constants.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const FALLBACK_ENTITY_PREFIX = 'taxFallback_'
export const SUPPORTED_PROVIDERS = ['avalara']
export const TAX_UPDATE_EVENT = 'taxFallback.taxUpdate'
export const VBASE_BUCKET = 'tax-fallback'
export const AVALARA_LOCK_PATH = 'avalara-lock'

export const MS_PER_DAY = 1000 * 60 * 60 * 24
export const DAYS_TO_TRIGGER_DOWNLOAD = 28

export const SCHEMA_VERSION = 'v1.1'

export const AVALARA_FIELDS = [
  'id',
  'date',
  'ZIP_CODE',
  'STATE_ABBREV',
  'COUNTY_NAME',
  'CITY_NAME',
  'STATE_SALES_TAX',
  'STATE_USE_TAX',
  'COUNTY_SALES_TAX',
  'COUNTY_USE_TAX',
  'CITY_SALES_TAX',
  'CITY_USE_TAX',
  'TOTAL_SALES_TAX',
  'TOTAL_USE_TAX',
  'TAX_SHIPPING_ALONE',
  'TAX_SHIPPING_AND_HANDLING_TOGETHER',
]
export const AVALARA_SCHEMA = {
  properties: {
    date: {
      type: 'string',
      title: 'Date',
    },
    ZIP_CODE: {
      type: 'string',
      title: 'Zip Code',
    },
    STATE_ABBREV: {
      type: 'string',
      title: 'State Abbreviation',
    },
    COUNTY_NAME: {
      type: 'string',
      title: 'County Name',
    },
    CITY_NAME: {
      type: 'string',
      title: 'City Name',
    },
    STATE_SALES_TAX: {
      type: 'number',
      title: 'State Sales Tax',
    },
    STATE_USE_TAX: {
      type: 'number',
      title: 'State Use Tax',
    },
    COUNTY_SALES_TAX: {
      type: 'number',
      title: 'County Sales Tax',
    },
    COUNTY_USE_TAX: {
      type: 'number',
      title: 'County Use Tax',
    },
    CITY_SALES_TAX: {
      type: 'number',
      title: 'City Sales Tax',
    },
    CITY_USE_TAX: {
      type: 'number',
      title: 'City Use Tax',
    },
    TOTAL_SALES_TAX: {
      type: 'number',
      title: 'Total Sales Tax',
    },
    TOTAL_USE_TAX: {
      type: 'number',
      title: 'Total Use Tax',
    },
    TAX_SHIPPING_ALONE: {
      type: 'boolean',
      title: 'Shipping is Taxable',
    },
    TAX_SHIPPING_AND_HANDLING_TOGETHER: {
      type: 'boolean',
      title: 'Shipping and Handling Together are Taxable',
    },
  },
  'v-indexed': [
    'date',
    'ZIP_CODE',
    'STATE_ABBREV',
    'COUNTY_NAME',
    'CITY_NAME',
    'STATE_SALES_TAX',
    'STATE_USE_TAX',
    'COUNTY_SALES_TAX',
    'COUNTY_USE_TAX',
    'CITY_SALES_TAX',
    'CITY_USE_TAX',
    'TOTAL_SALES_TAX',
    'TOTAL_USE_TAX',
    'TAX_SHIPPING_ALONE',
    'TAX_SHIPPING_AND_HANDLING_TOGETHER',
  ],
  'v-default-fields': [
    'date',
    'ZIP_CODE',
    'STATE_ABBREV',
    'COUNTY_NAME',
    'CITY_NAME',
    'STATE_SALES_TAX',
    'STATE_USE_TAX',
    'COUNTY_SALES_TAX',
    'COUNTY_USE_TAX',
    'CITY_SALES_TAX',
    'CITY_USE_TAX',
    'TOTAL_SALES_TAX',
    'TOTAL_USE_TAX',
    'TAX_SHIPPING_ALONE',
    'TAX_SHIPPING_AND_HANDLING_TOGETHER',
  ],
  'v-cache': false,
}

```


[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 tax-fallback/node/index.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  ClientsConfig,
  LRUCache,
  method,
  Service,
  ServiceContext,
  EventContext,
  RecorderState,
} from '@vtex/api'

import { Clients } from './clients'
import {
  getFallbackByPostalCode,
  downloadFallbackTable,
  updateTax,
} from './middlewares/fallback'
import { throttle } from './middlewares/throttle'

const TIMEOUT_MS = 10000

const memoryCache = new LRUCache<string, any>({ max: 5000 })

metrics.trackCache('tax-fallback', memoryCache)

const clients: ClientsConfig<Clients> = {
  implementation: Clients,
  options: {
    default: {
      retries: 1,
      timeout: TIMEOUT_MS,
    },
    avalara: {
      memoryCache,
    },
  },
}

declare global {
  // We declare a global Context type just to avoid re-writing ServiceContext<Clients, State> in every handler and resolver
  type Context = ServiceContext<Clients, State>
  type EventCtx = EventContext<Clients>

  // The shape of our State object found in `ctx.state`. This is used as state bag to communicate between middlewares.
  interface State extends RecorderState {
    country: string
    provider: string
    postalCode: string
  }
}

// Export a service that defines route handlers and client options.
export default new Service({
  clients,
  routes: {
    getFallbackTaxes: method({
      GET: getFallbackByPostalCode,
    }),
    downloadFallbackTaxes: method({
      POST: downloadFallbackTable,
    }),
  },
  events: {
    taxUpdate: [throttle, updateTax],
  },
})

```


[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 tax-fallback/node/clients/avalara.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  ExternalClient,
  InstanceOptions,
  IOContext,
  Apps,
  // IOResponse,
} from '@vtex/api'

function createBasicAuthHeader(account: string, licenseKey: string) {
  const base64Encoded = Buffer.from(`${account}:${licenseKey}`).toString(
    'base64'
  )

  return `Basic ${base64Encoded}`
}

export default class Avalara extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super('http://sandbox-rest.avatax.com/api/v2/', context, options)
  }

  public async downloadTaxRatesByZipCode(date: string): Promise<string> {
    const apps = new Apps(this.context)
    const appId = process.env.VTEX_APP_ID as string
    const settings = await apps.getAppSettings(appId)

    if (!settings.avalaraLogin || !settings.avalaraPassword) return ''

    const authorization = createBasicAuthHeader(
      settings.avalaraLogin,
      settings.avalaraPassword
    )

    return this.http.get(`taxratesbyzipcode/download/${date}`, {
      headers: {
        Authorization: authorization,
        'X-Vtex-Use-Https': true,
        'Content-Type': 'application/json;charset=UTF-8',
      },
      metric: 'downloadTaxRatesByZipCode',
    })
  }
}

```


[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 tax-fallback/node/clients/index.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { IOClients } from '@vtex/api'

import Avalara from './avalara'

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {
  public get avalara() {
    return this.getOrSet('avalara', Avalara)
  }
}

```


[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 tax-fallback/node/middlewares/throttle.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { TooManyRequestsError } from '@vtex/api'

const MAX_REQUEST = 10
let COUNTER = 0

export async function throttle(_ctx: EventCtx, next: () => Promise<unknown>) {
  COUNTER++

  try {
    if (COUNTER > MAX_REQUEST) {
      throw new TooManyRequestsError()
    }

    await next()
  } finally {
    COUNTER--
  }
}

```


[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 tax-fallback/node/middlewares/fallback.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable no-console */
import {
  Apps,
  AuthenticationError,
  NotFoundError,
  UserInputError,
  TooManyRequestsError,
} from '@vtex/api'
import parse from 'csv-parse/lib/sync'

import {
  TAX_UPDATE_EVENT,
  VBASE_BUCKET,
  AVALARA_LOCK_PATH,
  FALLBACK_ENTITY_PREFIX,
  SUPPORTED_PROVIDERS,
  AVALARA_SCHEMA,
  SCHEMA_VERSION,
  MS_PER_DAY,
  DAYS_TO_TRIGGER_DOWNLOAD,
} from '../constants'

interface TaxEntry {
  provider: string
  date: string
  TAX_SHIPPING_ALONE: boolean
  TAX_SHIPPING_AND_HANDLING_TOGETHER: boolean
  ZIP_CODE: string
  STATE_ABBREV: string
  COUNTY_NAME: string
  CITY_NAME: string
  STATE_SALES_TAX: number
  STATE_USE_TAX: number
  COUNTY_SALES_TAX: number
  COUNTY_USE_TAX: number
  CITY_SALES_TAX: number
  CITY_USE_TAX: number
  TOTAL_SALES_TAX: number
  TOTAL_USE_TAX: number
}

interface TaxLock {
  locked: boolean
}

const getAppId = (): string => {
  return process.env.VTEX_APP_ID ?? ''
}

function timeout(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function setupFallbackSchema(ctx: Context) {
  const {
    clients: { masterdata },
  } = ctx

  const { provider } = ctx.vtex.route.params

  const apps = new Apps(ctx.vtex)
  const app: string = getAppId()
  const settings = await apps.getAppSettings(app)

  if (
    settings[provider as string] &&
    settings[provider as string].hasSchema &&
    settings[provider as string].schemaVersion === SCHEMA_VERSION
  )
    return settings

  if (!settings[provider as string]) {
    settings[provider as string] = {}
  }

  try {
    await masterdata
      .createOrUpdateSchema({
        dataEntity: `${FALLBACK_ENTITY_PREFIX}${provider}`,
        schemaName: SCHEMA_VERSION,
        schemaBody: provider === 'avalara' ? AVALARA_SCHEMA : {},
      })
      .then(() => {
        settings[provider as string].hasSchema = true
        settings[provider as string].schemaVersion = SCHEMA_VERSION
      })
      .catch((e: any) => {
        settings[provider as string].hasSchema = false
        // eslint-disable-next-line vtex/prefer-early-return
        if (e.response.status === 304) {
          settings[provider as string].hasSchema = true
          settings[provider as string].schemaVersion = SCHEMA_VERSION
        }
      })
  } catch (e) {
    settings[provider as string].hasSchema = false
  }

  await apps.saveAppSettings(app, settings)

  return settings
}

export async function saveFallbackSchema(
  ctx: Context,
  next: () => Promise<void>
) {
  const { headers } = ctx

  const { provider } = ctx.vtex.route.params

  if (!provider) {
    throw new UserInputError('Provider must be provided')
  }

  if (!SUPPORTED_PROVIDERS.includes(provider.toString())) {
    throw new UserInputError('Invalid provider provided')
  }

  const settings = await setupFallbackSchema(ctx)

  settings.adminSetup.appVersion = process.env.VTEX_APP_VERSION

  ctx.status = 200
  ctx.body = settings
  ctx.set('Cache-Control', headers['cache-control'])

  await next()
}

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

  const { provider, postalCode } = ctx.vtex.route.params

  if (!provider) {
    throw new UserInputError('Provider must be provided')
  }

  if (!SUPPORTED_PROVIDERS.includes(provider.toString())) {
    throw new UserInputError('Invalid provider provided')
  }

  if (!postalCode) {
    throw new UserInputError('Postal code must be provided')
  }

  if (postalCode.length !== 5 || !/^\d+$/.test(postalCode.toString())) {
    throw new UserInputError(
      'Postal code must be provided as a five-digit string'
    )
  }

  const path = `${provider}-${postalCode}`

  const data: TaxEntry = await vbase.getJSON(VBASE_BUCKET, path, true)

  if (!data) throw new NotFoundError(`No taxes found for ${postalCode}`)

  if (data?.date) {
    const taxDate = new Date(data.date).valueOf()
    const diff = Date.now() - taxDate

    if (diff / MS_PER_DAY > DAYS_TO_TRIGGER_DOWNLOAD) {
      logger.info({
        message:
          'Avalara: download of new fallback table triggered (expired date)',
      })
      downloadFallbackTableAvalara(ctx).catch(() => {})
    }
  }

  ctx.status = 200
  ctx.body = data
  ctx.set('Cache-Control', headers['cache-control'])

  await next()
}

async function downloadFallbackTableAvalara(ctx: Context) {
  const {
    vtex: { logger },
    clients: { events, avalara, vbase },
  } = ctx

  const checkLock: TaxLock = await vbase.getJSON(
    VBASE_BUCKET,
    AVALARA_LOCK_PATH,
    true
  )

  if (checkLock?.locked) {
    return
  }

  const date = new Date()
  const formattedDate = date.toISOString().slice(0, 10)

  await avalara
    .downloadTaxRatesByZipCode(formattedDate)
    .catch(e => {
      logger.error({
        message: `Avalara: Failed to download new fallback table`,
        error: e,
      })
      throw new NotFoundError('Failed to download new fallback table')
    })
    .then(async response => {
      if (!response) {
        logger.error({
          message: `Avalara: Failed to download new fallback table (null response)`,
        })
        throw new NotFoundError(
          'Failed to download new fallback table (null response)'
        )
      }

      await vbase
        .saveJSON(VBASE_BUCKET, AVALARA_LOCK_PATH, { locked: true })
        .catch(() => {})

      return parse(response, {
        columns: true,
      })
    })
    .then(async (parsed: any[]) => {
      for (const row of parsed) {
        // eslint-disable-next-line no-await-in-loop
        await timeout(50)
        events.sendEvent('vtex.tax-fallback', TAX_UPDATE_EVENT, {
          provider: 'avalara',
          date: formattedDate,
          TAX_SHIPPING_ALONE: row.TAX_SHIPPING_ALONE === 'Y',
          TAX_SHIPPING_AND_HANDLING_TOGETHER:
            row.TAX_SHIPPING_AND_HANDLING_TOGETHER === 'Y',
          ZIP_CODE: row.ZIP_CODE,
          STATE_ABBREV: row.STATE_ABBREV,
          COUNTY_NAME: row.COUNTY_NAME,
          CITY_NAME: row.CITY_NAME,
          STATE_SALES_TAX: parseFloat(row.STATE_SALES_TAX),
          STATE_USE_TAX: parseFloat(row.STATE_USE_TAX),
          COUNTY_SALES_TAX: parseFloat(row.COUNTY_SALES_TAX),
          COUNTY_USE_TAX: parseFloat(row.COUNTY_USE_TAX),
          CITY_SALES_TAX: parseFloat(row.CITY_SALES_TAX),
          CITY_USE_TAX: parseFloat(row.CITY_USE_TAX),
          TOTAL_SALES_TAX: parseFloat(row.TOTAL_SALES_TAX),
          TOTAL_USE_TAX: parseFloat(row.TOTAL_USE_TAX),
        })
      }

      await vbase
        .saveJSON(VBASE_BUCKET, AVALARA_LOCK_PATH, { locked: false })
        .catch(() => {})
    })
}

export async function downloadFallbackTable(
  ctx: Context,
  next: () => Promise<void>
) {
  const {
    headers,
    clients: { apps, vbase },
  } = ctx

  const app: string = getAppId()
  const settings = await apps.getAppSettings(app)

  const { provider } = ctx.vtex.route.params

  if (!provider) {
    throw new UserInputError('Provider must be provided')
  }

  if (!SUPPORTED_PROVIDERS.includes(provider.toString())) {
    throw new UserInputError('Invalid provider provided')
  }

  if (provider === 'avalara') {
    if (!settings.avalaraLogin || !settings.avalaraPassword) {
      throw new AuthenticationError('Avalara credentials not found')
    }

    const checkLock: TaxLock = await vbase.getJSON(
      VBASE_BUCKET,
      AVALARA_LOCK_PATH,
      true
    )

    if (checkLock?.locked) {
      ctx.status = 200
      ctx.body = {
        msg: 'Update already in progress',
      }
      ctx.set('Cache-Control', headers['cache-control'])

      return next()
    }

    const date = new Date()
    const formattedDate = date.toISOString().slice(0, 10)

    const path = `avalara-98101` // this is the highest postal code in Avalara's table
    const checkDate: TaxEntry = await vbase.getJSON(VBASE_BUCKET, path, true)

    if (checkDate?.date === formattedDate) {
      ctx.status = 200
      ctx.body = {
        msg: 'Taxes are already up to date',
      }
      ctx.set('Cache-Control', headers['cache-control'])

      return next()
    }

    downloadFallbackTableAvalara(ctx)
  }

  ctx.status = 200
  ctx.body = {
    msg: 'Tax update initiated',
  }
  ctx.set('Cache-Control', headers['cache-control'])

  await next()
}

export async function updateTax(ctx: EventCtx, next: () => Promise<void>) {
  const {
    body,
    clients: { vbase },
    vtex: { logger },
  } = ctx

  if (!body.provider || !body.date || !body.ZIP_CODE || !body.TOTAL_SALES_TAX) {
    return next()
  }

  const path = `${body.provider}-${body.ZIP_CODE}`

  const existingData: TaxEntry | null = await vbase.getJSON(
    VBASE_BUCKET,
    path,
    true
  )

  if (existingData?.date) {
    const oldDate = new Date(existingData.date).valueOf()
    const newDate = new Date(body.date).valueOf()

    if (oldDate >= newDate) {
      return next()
    }
  }

  await vbase.saveJSON(VBASE_BUCKET, path, body).catch(error => {
    logger.warn({
      message: 'updateTax-error',
      error,
    })

    throw new TooManyRequestsError('Save to vbase request failed')
  })

  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 tax-fallback/node/__tests__/simple.test.ts from the tax-fallback VTEX app.

[Assistant]
Here's the implementation:

```typescript
// You can import your files here for testing them
//
// More info: https://github.com/sapegin/jest-cheat-sheet

describe('simpleTest', () => {
  it('one test case', async () => {
    expect(0.2 + 0.1).not.toBe(0.3)
  })
})

```


[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 storedash-proxy/graphql/schema.graphql from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```graphql
input StoreDashInput {
  appName: String!
  appVersion: String
  region: String
  production: String
  metricName: String!
  from: String!
  to: String!
  interval: String
  operation: String
  fields: [String]
  aggregateBy: [String]
  size: Int
  timezone: String
}

type Query {
  appsWithStats: [String]

  data (
    namespace: String!,
    name: String!,
    params: StoreDashInput,
    transformationType: String!,
  ): String @cacheControl(scope: PRIVATE)
}

```


[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 storedash-proxy/node/typings.d.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Registry, ServiceContext } from '@vtex/api'
import { StoreDashDataSource } from './dataSources/storedash'

declare global {
  interface Context extends ServiceContext {
    dataSources: DataSources
  }

  interface DataSources {
    storeDash: StoreDashDataSource
    registry: Registry
  }

  interface StoreDashInput {
    appName: string
    appVersion?: string
    region?: 'aws-us-east-1' | 'aws-us-east-2'
    production?: string
    metricName: string
    from: string
    to: string
    interval?: string
    operation?: string
    fields?: string[]
    aggregateBy?: string[]
    size?: number
    timezone?: 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 storedash-proxy/node/package.json from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "@vtex/api": "^1.5.2",
    "apollo-datasource-rest": "^0.1.5",
    "apollo-server": "^2.1.0",
    "apollo-server-errors": "^2.0.2",
    "bluebird": "^3.5.3",
    "graphql": "^14.0.2",
    "ramda": "^0.26.1"
  },
  "devDependencies": {
    "@types/bluebird": "^3.5.24",
    "@types/bluebird-global": "^3.5.9",
    "@types/node": "^10.7.1",
    "@types/ramda": "^0.25.45",
    "tslint": "^5.11.0",
    "tslint-config-vtex": "^2.0.0",
    "typescript": "^3.1.3"
  }
}

```


[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 storedash-proxy/node/index.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import * as Bluebird from 'bluebird'

global.Promise = Bluebird

import { dataSources } from './dataSources'
import { resolvers } from './resolvers'

export default {
  graphql: {
    dataSources,
    resolvers,
  },
}

```


[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 storedash-proxy/node/dataSources/storedash.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RequestOptions, RESTDataSource } from 'apollo-datasource-rest'
import { parse as parseCookie } from 'cookie'
import { addMeanProperty, changeToRelative, getTransformedParams, renameProperties, transformDataFormat } from './utils'

export class StoreDashDataSource extends RESTDataSource {
  constructor() {
    super()
  }

  public data = async (namespace: string, name: string, params: StoreDashInput, transformationType: string) => {
    const transformedParams: any = getTransformedParams(params)
    let responseData: any = await this.get(`/${namespace}/${name}?`, transformedParams)
    if (responseData && responseData[0]) {
      responseData = renameProperties('data.', responseData)
      addMeanProperty(responseData, params.metricName)
      responseData = changeToRelative(responseData, transformationType)
      responseData = transformDataFormat(responseData, transformationType)
    }
    return responseData
  }

  get baseURL() {
    const { vtex: { account } } = this.context
    return `http://api.vtex.com/api/storedash/${account}/metrics`
  }

  protected willSendRequest(request: RequestOptions) {
    const { header, vtex: { authToken } } = this.context
    const parsedCookies = parseCookie(header.cookie || '')
    const VtexIdclientAutCookie = parsedCookies.VtexIdclientAutCookie

    request.headers.set('X-Vtex-Use-Https', 'true')
    request.headers.set('VtexIdclientAutCookie', VtexIdclientAutCookie)
    request.headers.set('Proxy-Authorization', authToken)
  }
}

```


[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 storedash-proxy/node/dataSources/utils.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  adjust,
  curry,
  filter,
  forEach,
  forEachObjIndexed,
  fromPairs,
  groupBy,
  has,
  includes,
  isEmpty,
  isNil,
  join,
  keys,
  map,
  pipe,
  reject,
  replace,
  startsWith,
  toPairs,
} from 'ramda'

import { Fraction, UType } from './typings'

interface Params {
  [param: string]: string
}

interface Total {
  [date: string]: number
}

export const getTransformedParams = (params: StoreDashInput): Params => {
  const {
    appName = '',
    appVersion = '',
    region = '',
    production = '',
    metricName = '',
    aggregateBy = [],
    fields = [],
    ...otherParams
  } = params || {}

  return reject(isNilOrEmpty, {
    aggregateBy: join(',', aggregateBy),
    'data.key.name': metricName,
    'data.processEnv.appName': appName,
    'data.processEnv.appVersion': appVersion,
    'data.processEnv.production': production,
    'data.processEnv.region': region,
    fields: join(',', fields),
    ...otherParams,
  })
}

const isNilOrEmpty = x => isEmpty(x) || isNil(x)

const renameBy = (fn, obj) => (
  pipe(
    toPairs,
    map(adjust(0 as any, fn)),
    fromPairs
  )(obj)
)

export const renameProperties = (pattern: string, data: any) => {
  const regex = new RegExp('^' + pattern)
  return map(obj => renameBy(replace(regex, ''), obj), data)
}

const calculateMeanForObject = (metrics: string[], metricName: string, value: any, key: string | number | symbol, obj: any) => {
  if (includes(key, metrics) && obj.count) {
    if (metricName === 'cpuUsage') {
      obj[key] = obj[key] / obj.count
    } else {
      obj[key] = Math.round(obj[key] / obj.count)
    }
  }
}

// function to calculate mean of metrics different than custom format such
// as memoryUsage and cpuUsage
const calculateMeanForArray = (chartData: any[], metrics: string[], metricName: string) => {
  forEach((chartPoint: any) => {
    forEachObjIndexed(curry(calculateMeanForObject)(metrics, metricName), chartPoint)
  }, chartData)
}

// function to calculate mean of metrics in the custom format such as
// routeStats
const calculateMeanForArrayOfCustom = (chartData: any[]): void => {
  forEach((chartPoint: any) => {
    const sum: number = chartPoint['summary.sum']
    const count: number = chartPoint['summary.count']
    const mean = count ? (sum / count) : sum
    chartPoint['summary.mean'] = mean
  }, chartData)
}

export const addMeanProperty = (data: any[], metricName: string) => {
  if (metricName === 'memoryUsage') {
    const memoryMetrics = ['summary.external', 'summary.heapUsed', 'summary.heapTotal', 'summary.rss']
    calculateMeanForArray(data, memoryMetrics, metricName)
  } else if (metricName === 'cpuUsage') {
    const cpuMetrics = ['summary.system', 'summary.user']
    calculateMeanForArray(data, cpuMetrics, metricName)
  } else if (has('summary.sum', data[0])) {
    calculateMeanForArrayOfCustom(data)
  }
}

const changeToRelativeForStatusCodeLineChart = (data: any[]): any[] => {
  const total: Total = {}
  forEach(
    (dataPoint: any) => {
      const date: string = dataPoint.date
      if (!has(date, total)) {
        total[date] = 0
      }
      total[date] += dataPoint['summary.count']
    }
    , data
  )
  forEach(
    (dataPoint: any) => {
      dataPoint['summary.ratio'] = dataPoint['summary.count'] / total[dataPoint.date]
    }
    , data
  )
  return data
}

const changeToRelativeForStatusCodeBarChart = (data: object[]): any[] => {
  let total: number = 0
  forEach(
    (dataPoint: any) => {
      total += dataPoint['summary.count']
    }
    , data
  )
  forEach(
    (dataPoint: any) => {
      dataPoint['summary.ratio'] = dataPoint['summary.count'] / total
    }
    , data)
  return data
}

export const changeToRelative = (data: object[], transformationType: string): any[] => {
  switch (transformationType) {
    case 'StatusCodeBarChart':
      return changeToRelativeForStatusCodeBarChart(data)
    case 'StatusCodeLineChart':
      return changeToRelativeForStatusCodeLineChart(data)
    default:
      return data
  }
}

const transformToSimpleDateFormat = (data: any[]): UType => {
  return map(
    (element: any) => {
      const fraction: Fraction = {}
      fraction.id = element.date
      fraction.slices = []

      const desiredKeys = filter(
        (key: string) => {
          return startsWith('summary', key)
        }
        , keys(element))

      forEach(
        (key: string) => {
          fraction.slices.push(
            {
              content: [
                {
                  key: replace('summary.', '', key),
                  value: element[key],
                },
              ],
              sliceId: [],
            }
          )
        }
        , desiredKeys)
      return fraction
    }
    , data)
}

const transformToRouteStatsBarChartFormat = (data: any[]): UType => {
  return map(
    ({ 'key.httpStatus': httpStatus, 'summary.ratio': ratio }: any) => {
      const fraction: Fraction = {}
      fraction.id = httpStatus
      fraction.slices = [
        {
          content: [
            {
              key: 'ratio',
              value: ratio,
            },
          ],
          sliceId: [],
        },
      ]
      return fraction
    }
    , data)
}

const transformToAggregatedLineChartFormat = (data: any[], key: string): UType => {
  const aggregateByDate = groupBy(
    (element: any) => {
      return element.date
    }
    , data)

  const fractions: UType = []

  forEachObjIndexed(
    (elementsFromDate: any[], date: string) => {
      fractions.push(
        {
          id: date,
          slices: [],
        }
      )
      const lastIndex = fractions.length - 1
      forEach(
        (slice: any) => {
          fractions[lastIndex].slices.push(
            {
              content: [
                {
                  key,
                  value: slice[`summary.${key}`],
                },
              ],
              sliceId: [
                {
                  key: 'httpStatus',
                  value: slice['key.httpStatus'],
                },
              ],
            }
          )
        }
        , elementsFromDate)
    }
    , aggregateByDate)

  return fractions
}

export const transformDataFormat = (data: object[], transformationType: string): UType => {
  switch (transformationType) {
    case 'CpuUsageLineChart':
    case 'MemoryUsageLineChart':
      return transformToSimpleDateFormat(data)
    case 'StatusCodeBarChart':
      return transformToRouteStatsBarChartFormat(data)
    case 'StatusCodeLineChart':
      return transformToAggregatedLineChartFormat(data, 'ratio')
    case 'LatencyLineChart':
      return transformToAggregatedLineChartFormat(data, 'mean')
    default:
      return 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 storedash-proxy/node/dataSources/typings.d.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
export type UType = Fraction[]

export interface Fraction {
    id?: String
    slices?: Slices
}

export type Slices = Slice[]

export interface Slice {
    sliceId?: Obj<string, string>
    content?: Obj<string, number>
}

export type Obj<S, T> = ObjPair<S, T>[]

export interface ObjPair<S, T> {
    key?: S
    value?: T
}

```


[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 storedash-proxy/node/dataSources/index.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { DiskCache, LRUCache, MultilayeredCache, Registry } from '@vtex/api'
import { StoreDashDataSource } from './storedash'

import { CACHE_PATH } from '../common/globals'

const cacheStorage = new MultilayeredCache([
  new LRUCache<string, any>({
    max: 1000,
  }),
  new DiskCache(CACHE_PATH),
])

export const dataSources = () => ({
  registry: new Registry(null, {cacheStorage}),
  storeDash: new StoreDashDataSource(),
})

```


[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 storedash-proxy/node/resolvers/data.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Args {
  namespace: string,
  name: string,
  params: StoreDashInput
  transformationType: string
}

export const data = async (_, args: Args, ctx: Context) => {
  const { dataSources: { storeDash } } = ctx
  const { namespace, name, params, transformationType } = args

  return storeDash.data(namespace, name, params, transformationType)
    .then(JSON.stringify)
}

```


[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 storedash-proxy/node/resolvers/index.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { appsWithStats } from './appsWithStats'
import { data } from './data'

export const resolvers = {
  Query: {
    appsWithStats,
    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 storedash-proxy/node/resolvers/appsWithStats.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { filter, map, pluck, prop, replace, startsWith } from 'ramda'

const filterAppNameByAccount = (appNameList: string[], accountName: string) => {
  return filter(startsWith(accountName), appNameList)
}

const removeAccountInAppName = (appNameList: string[], accountName: string) => {
  return map(replace(accountName + '.', ''), appNameList)
}

export const appsWithStats = async (root, args, ctx: Context, info) => {
  const {dataSources: {registry}, vtex: {account}} = ctx
  const publishedAppsInThisAccount = await registry.listApps()
    .then(prop('data'))
    .then(pluck('partialIdentifier'))
    .then(result => filterAppNameByAccount(result, account))
    .then(result => removeAccountInAppName(result, account))
    .then(result => result.sort())

  return publishedAppsInThisAccount
}

```


[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 storedash-proxy/node/common/globals.ts from the storedash-proxy VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const CACHE_PATH = '/cache/console-immutable-assets/v0'

```


[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 supplier-provider-example/node/service.json from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 256,
  "ttl": 60,
  "timeout": 2,
  "minReplicas": 2,
  "maxReplicas": 4,
  "workers": 1,
  "routes": {
    "status": {
      "path": "/_v/status/:code",
      "public": true
    }
  }
}
```


[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 supplier-provider-example/node/package.json from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "co-body": "^6.0.0",
    "ramda": "^0.25.0"
  },
  "devDependencies": {
    "@types/co-body": "^0.0.3",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.0.0",
    "@types/ramda": "types/npm-ramda#dist",
    "@vtex/api": "6.45.15",
    "@vtex/test-tools": "^3.4.3",
    "@vtex/tsconfig": "^0.5.6",
    "typescript": "3.9.7"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty"
  },
  "version": "0.2.0"
}

```


[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 supplier-provider-example/node/index.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ClientsConfig, ServiceContext, RecorderState } from '@vtex/api'
import { LRUCache, method, Service } from '@vtex/api'

import { Clients } from './clients'
import { provideSuppliersUsingMiniCart } from './API/suppliers'

const TIMEOUT_MS = 800

// Create a LRU memory cache for the Status client.
// The @vtex/api HttpClient respects Cache-Control headers and uses the provided cache.
const memoryCache = new LRUCache<string, any>({ max: 5000 })

metrics.trackCache('status', memoryCache)

// This is the configuration for clients available in `ctx.clients`.
const clients: ClientsConfig<Clients> = {
  // We pass our custom implementation of the clients bag, containing the Status client.
  implementation: Clients,
  options: {
    // All IO Clients will be initialized with these options, unless otherwise specified.
    default: {
      retries: 2,
      timeout: TIMEOUT_MS,
    },
    // This key will be merged with the default options and add this cache to our Status client.
    supplierBuilder: {
      memoryCache,
    },
  },
}

declare global {
  // We declare a global Context type just to avoid re-writing ServiceContext<Clients, State> in every handler and resolver
  type Context = ServiceContext<Clients, State>

  // The shape of our State object found in `ctx.state`. This is used as state bag to communicate between middlewares.
  interface State extends RecorderState {
    code: number
  }
}

// Export a service that defines route handlers and client options.
export default new Service({
  clients,
  routes: {
    // `getSuppliers` is the route that must provide a supplier for the supplierBuilder
    getSuppliersByMiniCart: method({
      POST: [provideSuppliersUsingMiniCart],
    }),
  },
})

```


[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 supplier-provider-example/node/clients/index.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { IOClients } from '@vtex/api'

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {}

```


[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 supplier-provider-example/node/typings/protocolRequest.d.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
export type Item = {
  id: string
  name: string
  value: number
  quantity: number
  priceTags?: [
    {
      name: string
      value: number
      isPercentual: bool
    }
  ]
  components?: Item[]
  commission?: number
  freightCommission?: number
  sellerChain?: string[]
  shippingDiscout?: number
  discount?: number
  refId?: string
  productId?: string
  sellingPrice?: number
  sellerId?: string
  dockId?: string
  categoryId?: string
  categoryName?: string
  deliveryChannel?: string
  deliveryType?: string
  deliverySlaInMinutes?: Long
  deliveryWindow?: {
    startDate: Date
    endDate: Date
  }
  tax?: number
  freight?: number
}

export interface Seller {
  id: string
  name: string
  document: string
  documentType: string
}

export interface MiniCart {
  items: Item[]
  sellers?: Array<{
    id: string
    name: string
    document: string
    documentType: string
  }>
  freight?: number
  orderUrl?: string
  tax?: number
  shippingDate?: Date
  shippingEstimated?: string
  isGifftRegistry?: bool
  giftRegistryDescription?: string
  giftRegistryId?: string
  isPickupStore?: boolean
  isCallCenter?: bool
}

export interface RecipientsBuilderPayload {
  miniCart: MiniCart
  operationValue: number
  orderId: string
  transactionId: string
  operationValue?: number
  chargeProcessingFee?: boolean
  chargebackLiable?: boolean
  proportionalRefund?: string
  currency?: 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 supplier-provider-example/node/typings/supplier.d.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface Supplier {
  id: string
  name: string
  documentType: string
  document: string
  role: string
  amount: number
  commissionAmount: number
  chargeProcesssingFee: !boolean = false
  chargebackLiable: !boolean = false
}

```


[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 supplier-provider-example/node/business/suppliers.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { RecipientsBuilderPayload } from '../typings/protocolRequest'
import type { Supplier } from '../typings/supplier'

export function getSuppliersByMiniCart(payload: RecipientsBuilderPayload) {
  const operationValue = payload.operationValue ?? 100
  const supplier: Supplier = {
    id: 'mock',
    name: 'mocked',
    amount: operationValue,
    document: '1111',
    documentType: 'CNPJ',
    role: 'influencer',
    commissionAmount: 100,
    chargebackLiable: false,
    chargeProcesssingFee: false,
  }

  return [supplier]
}

```


[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 supplier-provider-example/node/__tests__/simple.test.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
// You can import your files here for testing them
//
// More info: https://github.com/sapegin/jest-cheat-sheet

describe('simpleTest', () => {
  it('one test case', async () => {
    expect(0.2 + 0.1).not.toBe(0.3)
  })
})

```


[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 supplier-provider-example/node/API/suppliers.ts from the supplier-provider-example VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { json } from 'co-body'

import { getSuppliersByMiniCart } from '../business/suppliers'

export async function provideSuppliersUsingMiniCart({
  req,
  response,
}: Context) {
  const payload = await json(req)
  const suppliers = getSuppliersByMiniCart(payload)

  response.status = 200
  response.body = suppliers
}

```


[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 shipping-option-components/messages/sl.json from the shipping-option-components VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/shipping-option-zipcode.deliverToButton.label": "Dostavi na naslov:",
  "store/shipping-option-zipcode.deliverToButton.placeholder": "Vpišite lokacijo",
  "store/shipping-option-zipcode.storeButton.label": "Trgovina:",
  "store/shipping-option-zipcode.storeButton.placeholder": "Izberi trgovino",
  "store/shipping-option-zipcode.deliverDrawer.title": "Oglejte si razpoložljivost za svojo regijo",
  "store/shipping-option-zipcode.pickupDrawer.title.empty": "Oglejte si trgovine v svoji regiji",
  "store/shipping-option-zipcode.pickupDrawer.title.filled": "Izberi trgovino",
  "store/shipping-option-zipcode.postalCodeInput.placeholder": "Vnesite svojo poštno številko",
  "store/shipping-option-zipcode.postalCodeInput.error": "Vnesena poštna številka ni na našem območju pokrivanja",
  "store/shipping-option-zipcode.currentLocationButton": "Uporabi trenutno lokacijo",
  "store/shipping-option-zipcode.storeHoursButton": "Oglejte si ure trgovine",
  "store/shipping-option-zipcode.viewMoreButton": "Poglej več",
  "store/shipping-option-zipcode.shippinFilter.title": "Možnosti pošiljanja",
  "store/shipping-option-zipcode.shippinFilter.deliverTo.title": "Pošlji v",
  "store/shipping-option-zipcode.shippinFilter.deliverTo.enterButton": "Vpišite lokacijo",
  "store/shipping-option-zipcode.shippinFilter.pkcupAt.title": "Prevzemi pri",
  "store/shipping-option-zipcode.shippinFilter.pkcupAt.chooseAStore": "Izberi trgovino",
  "store/shipping-option-zipcode.shippinFilter.pickupnearBy": "Prevzemite blizu",
  "store/shipping-option-zipcode.shippinFilter.pickpu": "Prevzemi",
  "store/shipping-option-zipcode.updateButton.label": "Posodobi",
  "store/shipping-option-zipcode.popoverButton.label": "Izberite lokacijo",
  "store/shipping-option-zipcode.popover.description": "Možnosti dostave in hitrost se lahko razlikujejo glede na naslov dostave in trgovino"
}

```