[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 sponsored-banners/react/utils/__test__/getDataProperties.test.tsx from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { getDataProperties } from '../getDataProperties'

describe('getDataProperties', () => {
  const response = getDataProperties({
    adResponseId: '123',
    advertisement: {
      bannerImageId: '1',
      imageUrl: 'www.image.com.br',
      targetUrl: 'www.target.com.br',
      width: 970,
      height: 250,
    },
  })

  it('should return the correct data properties', () => {
    expect(response).toEqual({
      'data-van-aid': '1',
      'data-van-banner-imageid': '1',
      'data-van-res-id': '123',
    })
  })
})

```


[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 sponsored-banners/react/components/SponsoredBanner/SponsoredBanner.tsx from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

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

import { useSponsoredBanner } from './useSponsoredBanner'
import { getDataProperties } from '../../utils'
import type { SponsoredBannersProps } from '../../interfaces'

const CSS_HANDLES = ['bannerWrapper', 'bannerImage'] as const

export const SponsoredBanner = (props: SponsoredBannersProps) => {
  const handles = useCssHandles(CSS_HANDLES)
  const { sponsoredBanners, error, loading, styleProps, imageAlt } =
    useSponsoredBanner(props)

  if (
    !props.showBanner ||
    !!error ||
    !sponsoredBanners ||
    sponsoredBanners.length === 0
  ) {
    return null
  }

  const banner = sponsoredBanners[0]
  const dataProperties = getDataProperties(banner)

  return (
    <div
      {...dataProperties}
      data-testid="banner"
      className={`${handles.bannerWrapper} flex justify-center items-center`}
      style={{
        maxWidth: banner.advertisement.width,
        height: 'auto',
        aspectRatio: `${styleProps.ratio}`,
        margin: '0 auto',
      }}
    >
      {loading ? (
        <Spinner size={styleProps.spinnerSize} />
      ) : (
        <a
          href={banner.advertisement.targetUrl}
          style={{
            padding: 0,
            border: 'none',
            background: 'none',
            cursor: 'pointer',
          }}
        >
          <img
            className={handles.bannerImage}
            src={banner.advertisement.imageUrl}
            alt={imageAlt}
            style={{
              width: banner.advertisement.width,
              height: 'auto',
              aspectRatio: `${styleProps.ratio}`,
            }}
          />
        </a>
      )}
    </div>
  )
}

SponsoredBanner.defaultProps = {
  adUnit: 'billboard',
  showBanner: true,
}

SponsoredBanner.schema = {
  title: 'store/sponsored-banner',
  type: 'object',
  properties: {
    adUnit: {
      type: 'string',
      title: 'admin/editor.ad-unit',
      default: 'billboard',
      enum: ['billboard'],
      enumNames: ['970px x 250px'],
    },
    showBanner: {
      type: 'boolean',
      title: 'admin/editor.show-banner',
      default: 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 sponsored-banners/react/components/SponsoredBanner/useSponsoredBanner.ts from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useQuery } from 'react-apollo'
import { useIntl } from 'react-intl'
import { useDevice } from 'vtex.device-detector'

import sponsoredBannersQuery from '../../query'
import messages from '../../messages'
import type {
  SponsoredBannersData,
  SponsoredBannersProps,
} from '../../interfaces'

const SPONSORED_COUNT = 1

export function useSponsoredBanner({
  adUnit,
  placement = 'homepage',
  channel = 'website',
}: SponsoredBannersProps) {
  const { formatMessage } = useIntl()
  const { device } = useDevice()
  const isDesktop = device === 'desktop'

  const { data, loading, error } = useQuery<SponsoredBannersData>(
    sponsoredBannersQuery,
    {
      variables: {
        sponsoredCount: SPONSORED_COUNT,
        placement,
        adUnit,
        channel,
      },
    }
  )

  const imageAlt = formatMessage(messages.sponsoredBanner)

  const styleProps = {
    spinnerSize: isDesktop ? 40 : 20,
    ratio:
      data && data.sponsoredBanners.length > 0
        ? data.sponsoredBanners[0].advertisement.width /
          data.sponsoredBanners[0].advertisement.height
        : 0,
  }

  return {
    sponsoredBanners: data?.sponsoredBanners ?? [],
    loading,
    error,
    styleProps,
    imageAlt,
  }
}

```


[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 sponsored-banners/react/components/SponsoredBanner/__test__/useSponsoredBanner.test.ts from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useQuery } from 'react-apollo'
import { renderHook } from '@vtex/test-tools/react'
import { useDevice } from 'vtex.device-detector'

import { mockData, mockProps } from './mocks'
import { useSponsoredBanner } from '../useSponsoredBanner'

jest.mock('react-apollo', () => ({
  useQuery: jest.fn(),
}))

jest.mock('react-intl', () => ({
  defineMessages: jest.fn().mockImplementation(() => ({
    sponsoredBanner: 'sponsoredBanner',
  })),
  useIntl: jest.fn().mockReturnValue({
    formatMessage: jest.fn().mockImplementation((text) => text),
  }),
}))

jest.mock('vtex.device-detector', () => ({
  useDevice: jest.fn(),
}))

jest.mock('../../../query', () => ({
  sponsoredBannersQuery: jest.fn(),
}))

describe('useSponsoredBanner hook', () => {
  describe('when it has data without error', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: mockData,
        loading: false,
        error: null,
      })
      ;(useDevice as jest.Mock).mockReturnValue({ device: 'desktop' })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(false)
      expect(result.current.error).toBeNull()
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 3.88,
      })

      expect(result.current.sponsoredBanners).toEqual([
        {
          adResponseId: '123',
          advertisement: {
            bannerImageId: '1',
            imageUrl: 'www.image.com.br',
            targetUrl: 'www.target.com.br',
            width: 970,
            height: 250,
          },
        },
      ])
    })

    it('should return correct values for mobile', () => {
      ;(useDevice as jest.Mock).mockReturnValueOnce({ device: 'mobile' })

      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.styleProps).toEqual({
        spinnerSize: 20,
        ratio: 3.88,
      })
    })
  })

  describe('when it has error', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: null,
        loading: false,
        error: 'error',
      })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(false)
      expect(result.current.error).toBe('error')
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 0,
      })

      expect(result.current.sponsoredBanners).toEqual([])
    })
  })

  describe('when it has no data', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: null,
        loading: false,
        error: null,
      })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(false)
      expect(result.current.error).toBeNull()
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 0,
      })

      expect(result.current.sponsoredBanners).toEqual([])
    })
  })

  describe('when it has no data in the array', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: { sponsoredBanners: [] },
        loading: false,
        error: null,
      })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(false)
      expect(result.current.error).toBeNull()
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 0,
      })

      expect(result.current.sponsoredBanners).toEqual([])
    })
  })

  describe('when loading is true and it has no data', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: null,
        loading: true,
        error: null,
      })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(true)
      expect(result.current.error).toBeNull()
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 0,
      })

      expect(result.current.sponsoredBanners).toEqual([])
    })
  })

  describe('when loading is true and it has ]] data', () => {
    beforeEach(() => {
      ;(useQuery as jest.Mock).mockReturnValue({
        data: mockData,
        loading: true,
        error: null,
      })
    })

    it('should return correct values', () => {
      const { result } = renderHook(() => useSponsoredBanner(mockProps))

      expect(result.current.loading).toBe(true)
      expect(result.current.error).toBeNull()
      expect(result.current.imageAlt).toBe('sponsoredBanner')

      expect(result.current.styleProps).toEqual({
        spinnerSize: 40,
        ratio: 3.88,
      })

      expect(result.current.sponsoredBanners).toEqual([
        {
          adResponseId: '123',
          advertisement: {
            bannerImageId: '1',
            imageUrl: 'www.image.com.br',
            targetUrl: 'www.target.com.br',
            width: 970,
            height: 250,
          },
        },
      ])
    })
  })
})

```


[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 sponsored-banners/react/components/SponsoredBanner/__test__/SponsoredBanner.test.tsx from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

```tsx
import '@testing-library/jest-dom'
import React from 'react'
import { render } from '@vtex/test-tools/react'

import { SponsoredBanner } from '../SponsoredBanner'
import { useSponsoredBanner } from '../useSponsoredBanner'
import { mockData } from './mocks'

jest.mock('../useSponsoredBanner', () => ({
  useSponsoredBanner: jest.fn(),
}))

describe('SponsoredBanner component', () => {
  describe('when there are banners available', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: mockData.sponsoredBanners,
        imageAlt: 'Alt da imagem',
        loading: false,
        error: null,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('renders the sponsored banners image', () => {
      const { getByAltText, getByTestId } = render(<SponsoredBanner />)
      const banner = getByTestId('banner')
      const image = getByAltText('Alt da imagem')

      expect(banner).toBeInTheDocument()
      expect(image).toBeInTheDocument()
      expect(image).toHaveAttribute('src', 'www.image.com.br')
    })

    it('render href correctly', () => {
      const { getByAltText } = render(<SponsoredBanner />)
      const image = getByAltText('Alt da imagem')

      expect(image.parentElement).toHaveAttribute('href', 'www.target.com.br')
    })

    it('render width and ratio correctly correctly', () => {
      const { getByTestId, getByAltText } = render(<SponsoredBanner />)

      const banner = getByTestId('banner')
      const image = getByAltText('Alt da imagem')

      expect(banner.style.maxWidth).toBe('970px')
      expect(banner.style.aspectRatio).toBe('3')
      expect(image.style.width).toBe('970px')
      expect(image.style.aspectRatio).toBe('3')
    })

    it('render data analytics correctly', () => {
      const { getByTestId } = render(<SponsoredBanner />)
      const banner = getByTestId('banner')

      expect(banner).toHaveAttribute('data-van-aid', '1')
      expect(banner).toHaveAttribute('data-van-banner-imageid', '1')
      expect(banner).toHaveAttribute('data-van-res-id', '123')
    })
  })

  describe('when loading is true', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: mockData.sponsoredBanners,
        imageAlt: 'Alt da imagem',
        loading: true,
        error: null,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('render the banner, but does not render the image', () => {
      const { queryByAltText, queryByTestId } = render(<SponsoredBanner />)
      const banner = queryByTestId('banner')
      const image = queryByAltText('Alt da imagem')

      expect(banner).toBeTruthy()
      expect(image).toBeNull()
    })
  })

  describe('when showBanner prop is false', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: mockData.sponsoredBanners,
        imageAlt: 'Alt da imagem',
        loading: false,
        error: null,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('does not render the banner', () => {
      const { queryByAltText, queryByTestId } = render(
        <SponsoredBanner showBanner={false} />
      )

      const banner = queryByTestId('banner')
      const image = queryByAltText('Alt da imagem')

      expect(banner).toBeNull()
      expect(image).toBeNull()
    })
  })

  describe('when it has any error', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: mockData.sponsoredBanners,
        imageAlt: 'Alt da imagem',
        loading: false,
        error: true,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('does not render the banner', () => {
      const { queryByAltText, queryByTestId } = render(<SponsoredBanner />)
      const banner = queryByTestId('banner')
      const image = queryByAltText('Alt da imagem')

      expect(banner).toBeNull()
      expect(image).toBeNull()
    })
  })

  describe('when sponsored banners is null', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: null,
        imageAlt: 'Alt da imagem',
        loading: false,
        error: null,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('does not render the banner', () => {
      const { queryByAltText, queryByTestId } = render(<SponsoredBanner />)
      const banner = queryByTestId('banner')
      const image = queryByAltText('Alt da imagem')

      expect(banner).toBeNull()
      expect(image).toBeNull()
    })
  })

  describe('when sponsored banner is empty array', () => {
    beforeEach(() => {
      ;(useSponsoredBanner as jest.Mock).mockReturnValue({
        sponsoredBanners: [],
        imageAlt: 'Alt da imagem',
        loading: false,
        error: null,
        styleProps: {
          spinnerSize: 40,
          ratio: 3,
        },
      })
    })

    it('does not render the banner', () => {
      const { queryByAltText, queryByTestId } = render(<SponsoredBanner />)
      const banner = queryByTestId('banner')
      const image = queryByAltText('Alt da imagem')

      expect(banner).toBeNull()
      expect(image).toBeNull()
    })
  })
})

```


[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 sponsored-banners/react/components/SponsoredBanner/__test__/mocks/index.ts from the sponsored-banners VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type {
  SponsoredBannersData,
  SponsoredBannersProps,
} from '../../../../interfaces'

export const mockData: SponsoredBannersData = {
  sponsoredBanners: [
    {
      adResponseId: '123',
      advertisement: {
        bannerImageId: '1',
        imageUrl: 'www.image.com.br',
        targetUrl: 'www.target.com.br',
        width: 970,
        height: 250,
      },
    },
  ],
}

export const mockProps: SponsoredBannersProps = {
  adUnit: 'billboard',
  placement: 'homepage',
  channel: 'android',
}

```


[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 render-runtime/docs/README.md from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Render Runtime

The Render Runtime app is responsible for handling runtime execution of React apps in the VTEX IO Platform. Additionally, it exports:

- Helpful variables, such as [`canUseDOM`](#canusedom).
- Hooks, such as [`useRuntime`](#useruntime).
- React components, such as [`Block` (alias `ExtensionPoint`)](#block-alias-extensionpoint), [`Helmet`](#helmet), [`Link`](#link), [`NoSSR`](#nossr) and [`withRuntimeContext`](#withruntimecontext-high-order-component).

> ℹ **Tip:** Run vtex setup --typings to add vtex.render-runtime types in your app. This way, IDEs will be able to provide autocomplete for variables and methods.

Check the following sections for more information on the objects exported by the Render Runtime app.

# Variables

## canUseDOM

A *boolean* value that indicates whether the code is running in a browser environment (`true`) or in a Node/SSR environment (`false`).

> ℹ Notice that the `canUseDOM` variable is especially useful in cases the components use DOM related data _(e.g: `document` or `window`)_.

Take the following usage example:

```tsx
import React from 'react'
import { canUseDOM } from 'vtex.render-runtime'

function MyComponent() {
  const data = canUseDOM
    ? window.localStorage.getItem('foo')
    : ''

  return
Hello

}

export default MyComponent
```

# Hooks

## useRuntime

The `useRuntime` React hook is useful when creating components since it provides runtime contextual variables and methods.

For an example on its usage, check the following snippet:

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const runtime = useRuntime()

  return
Hello

}
```

Inside the `runtime` object you can have access to the following variables:

| Name          | Type   | Description              |
|:--------------|:-------|:-------------------------|
|[`account`](#account)     |string  |The VTEX account name, (e.g., `storecomponents`).    |
|[`binding`](#binding)     |object  |An object containing the `id` and `canonicalBaseAddress` of the store binding. |
|[`culture`](#culture)      |object  |An object containing culture, currency and locale information. |
|[`deviceInfo`](#deviceinfo)  |object  |An object specifying the user device type (`phone`, `desktop`, `tablet`, or `unknown`). *This data varies when the user resizes the window.*|
|[`getSettings`](#getsettings)  |function|A function that, when called, returns the public `settings` of an app.|
|[`hints`](#hints)      |object  | An object which specifies the user device type (`phone`, `desktop`, `tablet`, or `unknown`) based on the information provided by the CDN. *Different from `deviceInfo` this data is static.*|
|[`history`](#history)|object  |A `history` object reexported from the `history` package. For further information, check [this link.](https://github.com/ReactTraining/history/tree/v4/docs)|
|[`navigate`](#navigate)|function|A function used in the client-side to define the navigation behaviour. |
|[`page`](#page)|string  |The current `page` id (e.g., `store.home`).|
|[`pages`](#pages)|object  |Object containing all `pages`. The keys are the pages ids (e.g., `store.home`).|
|[`route`](#route)|object  |Object containing data related to the current route, such as `id`, `path`, `blockId` and others.|
|[`production`](#production)|boolean |Points if the app is in a production workspace (`true`) or not (`false`). |
|[`query`](#query)|object  |The URL query string values in a key-value format (e.g., `{ "foo": "bar" }`).|
|[`renderMajor`](#rendermajor)|number  |The major version of the Render Runtime app.|
|[`rootPath`](#rootpath)|string  |The store root path (e.g., `/ar`). If not specified, its value is `undefined`.|
|[`setQuery`](#setquery)|function|A function that can be called to set query string params.|
|[`workspace`](#workspace)|string  |The current workspace name (e.g., `master`).|

### Usage examples

Check the following section for usage examples on how to use the internal `runtime` variables.

#### `account`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { account } = useRuntime()

  return
Welcome to {account}

}

export default MyComponent
```

#### `binding`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { binding } = useRuntime()

  return
Canonical address is "{binding.canonicalBaseAddress}"

}

export default MyComponent
```

*Type:*

```tsx
interface BindingInfo {
  id: string
  canonicalBaseAddress: string
}
```

*Example value:*

```json
{
  "id": "aacb06b3-a8fa-4bab-b5bd-2d654d20dcd8",
  "canonicalBaseAddress": "storetheme.vtex.com/"
}
```

#### `culture`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { culture } = useRuntime()

  return
Current active locale is: "{culture.locale}"

}

export default MyComponent
```

*Type:*

```tsx
interface Culture {
  availableLocales: string[]
  country: string
  currency: string
  language: string
  locale: string
  customCurrencyDecimalDigits: number | null
  customCurrencySymbol: string | null
}
```

*Example value:*

```json
{
  "availableLocales": [],
  "country": "USA",
  "currency": "USD",
  "language": "en",
  "locale": "en-US",
  "customCurrencyDecimalDigits": null,
  "customCurrencySymbol": "$"
}
```

#### `deviceInfo`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { deviceInfo } = useRuntime()

  return
This page is being rendered on a "{deviceInfo.type}"

}

export default MyComponent
```

*Type:*
```tsx
interface DeviceInfo {
  isMobile: boolean
  type: 'phone' | 'tablet' | 'desktop' | 'unknown'
}
```

*Example value:*
```json
{
  "isMobile": false,
  "type": "desktop"
}
```

#### `getSettings`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { getSettings } = useRuntime()
  const settings = getSettings('vtex.store')

  return
This is the store's name: "{settings.storeName}"

}

export default MyComponent
```

#### `hints`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { hints } = useRuntime()

  if (!hints.desktop) {
    return
This is not a desktop

  }

  return
This is a desktop

}

export default MyComponent
```

*Type:*

```tsx
interface Hints {
  desktop: boolean
  mobile: boolean
  tablet: boolean
  phone: boolean
  unknown: boolean
}
```

*Example value:*

```json
{
  "desktop": true,
  "mobile": false,
  "tablet": false,
  "phone": false,
  "unknown": false,
}
```

#### `history`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { history } = useRuntime()

  const handleClick = () => {
    history.goBack()
  }

  return <button onClick={handleClick}>Back</button>
}

export default MyComponent
```

#### `navigate`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { navigate } = useRuntime()

  const handleClick = () => {
    navigate({
      to: '/other-page'
    })
  }

  return <button onClick={handleClick}>Go</button>
}

export default MyComponent
```

*Function param:*

```tsx
interface NavigateOptions {
  fallbackToWindowLocation?: boolean
  hash?: string
  page?: string
  params?: any
  query?: any
  replace?: boolean
  rootPath?: string
  scrollOptions?: false | {
    baseElementId: string,
    behavior: 'auto' | 'smooth'
    left: number
    top: number
  }
  skipSetPath?: boolean
  to?: string
}
```

#### `page`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { page } = useRuntime()

  return
This is the current page id: "{page}"

}

export default MyComponent
```

#### `pages`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { pages, page } = useRuntime()

  return
This is the current page declarer: "{pages[page].declarer}"

}

export default MyComponent
```

*Example value:*

```json
{
  "allowConditions": true,
  "context": null,
  "declarer": "vtex.store@2.x",
  "path": "/",
  "routeId": "store.home",
  "blockId": "vtex.store-theme@4.x:store.home",
  "map": []
}

```

#### `route`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { route } = useRuntime()

  return
This is the current route full path: "{route.path}"

}

export default MyComponent
```

*Example value:*

```json
{
  "domain": "store",
  "id": "store.home",
  "pageContext": {
    "id": "store.home",
    "type": "route"
  },
  "params": {},
  "path": "/",
  "pathId": "/",
  "queryString": {},
  "breakpointStyles": [
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.common.min.css",
      "mediaQuery": "",
      "type": "common"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.small.min.css",
      "mediaQuery": "screen and (min-width: 20em)",
      "type": "small"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.notsmall.min.css",
      "mediaQuery": "screen and (min-width: 40em)",
      "type": "notsmall"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.large.min.css",
      "mediaQuery": "screen and (min-width: 64em)",
      "type": "large"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.xlarge.min.css",
      "mediaQuery": "screen and (min-width: 80em)",
      "type": "xlarge"
    }
  ],
  "fonts": "/_v/public/vtex.styles-graphql/v1/fonts/7ead87572b7446c1ca01c45f5065665fc8cfd256",
  "overrides": [
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.product-list@0.28.2$overrides.css",
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.minicart@2.56.0$overrides.css",
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.store-theme@4.3.0$overrides.css"
  ],
  "rootName": "store.home",
  "ssr": true,
  "styleMeta": {
    "fontsHash": "7ead87572b7446c1ca01c45f5065665fc8cfd256",
    "overridesIds": [
      {
        "id": "vtex.product-list@0.28.2$overrides.css"
      },
      {
        "id": "vtex.minicart@2.56.0$overrides.css"
      },
      {
        "id": "vtex.store-theme@4.3.0$overrides.css"
      }
    ],
    "themeId": "vtex.store-theme@4.3.0$style.min.css"
  },
  "blockId": "vtex.store-theme@4.x:store.home",
  "canonicalPath": "/",
  "metaTags": null,
  "routeId": "store.home",
  "title": null,
  "varyContentById": false
}
```

#### `production`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { production } = useRuntime()

  if (!production) {
    return
This is not a production workspace

  }

  return
This is a production workspace

}

export default MyComponent
```

#### `query`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { query } = useRuntime()

  return
The current query strings are {JSON.stringify(query)}

}

export default MyComponent
```

#### `renderMajor`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { renderMajor } = useRuntime()

  return
This page is rendered using vtex.render-runtime@{renderMajor}.x

}

export default MyComponent
```

#### `rootPath`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { rootPath } = useRuntime()

  if (!rootPath) {
    return
The store doesn't have a rootPath set

  }

  return
The store rootPath is "{rootPath}"

}

export default MyComponent
```

#### `setQuery`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { setQuery } = useRuntime()

  const handleClick = () => {
    setQuery({ foo: 'bar' })
  }

  return <button>Set</button>
}

export default MyComponent
```

#### `workspace`

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { workspace } = useRuntime()

  return
This is the {workspace} workspace

}

export default MyComponent
```

# Components

## Block (alias ExtensionPoint)

`Block` is a React component used to create Store Framework blocks.

For implementation details, take the following example.

> ℹ *Notice that the `Block` component will always expect a specific block `id`.*

```tsx
import React from 'react'
import { Block } from 'vtex.render-runtime'
// or
// import { ExtensionPoint } from 'vtex.render-runtime'

function MyComponent() {
  return (

      Foobar
      <Block id="my-other-block" />
      {/* or <ExtensionPoint id="my-other-block" /> */}

  )
}

export default MyComponent
```

## Helmet

`Helmet` is a component used to add HTML tags inside the `<head>` tag of a page. Take the following example:

> ℹ `Helmet` is a reexport of [the `Helmet` component from the `react-helmet` library](https://github.com/nfl/react-helmet/tree/release/5.2.0).

```tsx
import React from 'react'
import { Helmet } from 'vtex.render-runtime'

function MyComponent() {
  return (
    <>
      <Helmet>
        <meta property="og:type" content="article" />
      </Helmet>
    </>
  )
}

export default MyComponent
```

## Link

The `Link` React component is responsible for rendering an `a` HTML element that, when clicked, navigates the user to the provided route.

> ℹ Notice that the `Link` component has a similar API to the `navigate` method from the [`useRuntime`](#useruntime) hook.

| Name      | Type          | Description | Default  |
| :------------- |:-------------| :-----|:-----|
| `page`     | `string`  | The name of the page that the user will be redirected to. Maps to a `blocks.json` block (e.g., `'store.product'`)||
| `to`     | `string`    |The URL of the page that the user will be redirected to (e.g., `/shirt/p?skuId=1`). Notice that `to` is an **alternative** to `page` and it contains the whole URL instead of the page name. | |
| `params` | `object`      | The `param` values of the page path in a key-value format (e.g, `{slug: 'shirt'}`). Params that starts with `__` are not considered on path transformations, and can be generaly be used as an alternative to query params | `{}`|
| `query` | `string`  | The representation of the query params that are appended to the page path (e.g., `skuId=231`.) | `''` |
| `onClick` | `function` | A callback that is fired when the user clicks on a component (e.g., `() => alert('Salut')`) | |
| `replace` | `boolean` | The boolean value used to indicate if it should call (`true`) the replace function to navigate or not (`false`) | |

Other props you pass will be forwarded to the `a` component and can be used for customization.

Take the following usage examples:

```tsx
import React from 'react'
import { Link } from 'vtex.render-runtime'

function MyComponent() {
  return <Link to="/otherpage" classname="c-on-base">Hello</Link>
}

export default MyComponent
```

```tsx
import React from 'react'
import { Link } from 'vtex.render-runtime'

function MyComponent() {
  const params = {
    slug: PRODUCT_SLUG, // Considered on path transformations (/{slug}/p)
    __listName: 'List of products' // Ignored on path transformations
    __yourProductPageParam: YOUR_PARAM // Ignored on path transformations
  }

  return <Link to="/productpage" params={params}>Hello</Link>
}

export default MyComponent
```

## NoSSR

> ⚠ We always recommend using the [`canUseDOM`](#canusedom) variable when possible.

`NoSSR` is a React component that avoids rendering its children during Server-Side Rendering (SSR).

> ℹ Notice that the `NoSSR` component is especially useful in cases the components use DOM related data _(e.g: `document` or `window`)_.

Take the following usage example:

```tsx
import React from 'react'
import { NoSSR } from 'vtex.render-runtime'

import DomRelatedComponent from './DomRelatedComponent'

function MyComponent() {
  return (
    <NoSSR onSSR={
Loading...
}>
      <DomRelatedComponent/>
    </NoSSR>
  )
}
```

## withRuntimeContext (High Order Component)

`withRuntimeContext` is a React High Order Component (HOC) that allows class components to access the runtime context.

> ℹ When using function components, you can use [`useRuntimeContext`](#useruntimecontext) hook instead.

Take the following usage example:

```tsx
import React from 'react'
import { withRuntimeContext, RenderContext } from 'vtex.render-runtime'

class MyComponent extends React.Component<{ runtime: RenderContext }>{
  render({ runtime }) {
    return
This is the current page id: "{runtime.page}"

  }
}

const MyComponentWithRuntime = withRuntimeContext(MyComponent)
```

Notice that, when in SSR mode, you can optionally provide the `onSSR` prop together with a component to render instead.

```


[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 render-runtime/react/index.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* global module */
import './o11y/instrument'
import 'core-js/es6/symbol'
import 'core-js/fn/symbol/iterator'
import { canUseDOM } from 'exenv'
import * as runtimeGlobals from './core/main'

import { polyfillIntl } from './start/intl'
import { addAMPProxy } from './start/amp'
import { patchLibs } from './start/patchLibs'
import { registerRuntimeGlobals } from './start/register'
import { loadRuntimeJSONs } from './start/runtime'
import { hydrateUncriticalStyles } from './start/styles'

function performanceMark(...args: Parameters<typeof window.performance.mark>) {
  if (
    typeof window === 'undefined' ||
    !(typeof window?.performance?.mark === 'function')
  ) {
    return
  }
  window.performance.mark(...args)
}

const uncriticalStylesPromise = hydrateUncriticalStyles()
performanceMark('uncritical-styles-start')
uncriticalStylesPromise.then(() => {
  performanceMark('uncritical-styles-end')
})

performanceMark('intl-polyfill-start')
const intlPolyfillPromise = polyfillIntl()
intlPolyfillPromise.then(() => {
  performanceMark('intl-polyfill-end')
})

registerRuntimeGlobals(runtimeGlobals)
addAMPProxy(window.__RUNTIME__)
patchLibs()

export const renderReadyPromise: Promise<any> = canUseDOM
  ? (function () {
      const contentLoadedPromise = new Promise((resolve) => {
        window.addEventListener('DOMContentLoaded', resolve)
        if (window.__DOM_READY__) {
          resolve()
        }
      })

      contentLoadedPromise.then(() => {
        performanceMark('content-loaded-promise-resolved')
      })

      const scriptsLoadedPromise = new Promise((resolve) => {
        if (typeof window.__ASYNC_SCRIPTS_READY__ === 'undefined') {
          return resolve()
        }

        window.addEventListener('asyncScriptsReady', resolve)
        if (window.__ASYNC_SCRIPTS_READY__) {
          resolve()
        }
      })

      return Promise.all([
        contentLoadedPromise,
        intlPolyfillPromise,
        scriptsLoadedPromise,
        uncriticalStylesPromise,
      ])
    })()
  : Promise.resolve()

function start() {
  global.__RUNTIME__ = window.__RUNTIME__
  if (window.__RUNTIME__.start && !window.__ERROR__) {
    if (canUseDOM) {
      renderReadyPromise.then(() => {
        setTimeout(() => {
          performanceMark('render-start')
          window.__RENDER_8_RUNTIME__.start()
          performanceMark('render-end')
          window?.performance?.measure?.(
            '[VTEX IO] Rendering/Hydration',
            'render-start',
            'render-end'
          )
        }, 1)
      })
    } else {
      window.__RENDER_8_RUNTIME__.start()
    }
  }
}

if (module.hot) {
  module.hot.accept('./core/main', () => {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const hotGlobals = require('./core/main')
    window.__RENDER_8_RUNTIME__.ExtensionContainer =
      hotGlobals.ExtensionContainer
    window.__RENDER_8_RUNTIME__.ExtensionPoint = hotGlobals.ExtensionPoint
    window.__RENDER_8_RUNTIME__.LayoutContainer = hotGlobals.LayoutContainer
    window.__RENDER_8_RUNTIME__.Link = hotGlobals.Link
    window.__RENDER_8_RUNTIME__.Loading = hotGlobals.Loading
    window.__RENDER_8_RUNTIME__.buildCacheLocator = hotGlobals.buildCacheLocator
    runtimeGlobals.start()
  })
}

if (!canUseDOM) {
  start()
} else {
  loadRuntimeJSONs().then(() => start())
}

export * from './core/main'

```


[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 render-runtime/react/intl-polyfill.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { path } from 'ramda'
import { canUseDOM } from 'exenv'

import { PluralRules } from '@formatjs/intl-pluralrules'
import RelativeTimeFormat from '@formatjs/intl-relativetimeformat'

let myPromise = null

if (typeof window.Intl.PluralRules === 'undefined' || !canUseDOM) {
  Object.defineProperty(Intl, 'PluralRules', {
    value: PluralRules,
    writable: true,
    enumerable: false,
    configurable: true,
  })
}

if (!('RelativeTimeFormat' in Intl) || !canUseDOM) {
  Object.defineProperty(Intl, 'RelativeTimeFormat', {
    value: RelativeTimeFormat,
    writable: true,
    enumerable: false,
    configurable: true,
  })
}

const locale = path<string>(['__RUNTIME__', 'culture', 'locale'], window)
const [lang] = locale ? locale.split('-') : ['']

myPromise = new Promise((resolve) => {
  const hasPolyfilledPlural =
    window.Intl.PluralRules.polyfilled && canUseDOM && lang
  const hasPolyfilledRelative =
    window.Intl.RelativeTimeFormat.polyfilled && canUseDOM && lang

  const pluralPromise = hasPolyfilledPlural
    ? import('@formatjs/intl-pluralrules/dist/locale-data/' + lang)
    : Promise.resolve()
  const relativeTimePromise = hasPolyfilledRelative
    ? import('@formatjs/intl-relativetimeformat/dist/locale-data/' + lang)
    : Promise.resolve()
  Promise.all([pluralPromise, relativeTimePromise]).then(resolve)
})

export default myPromise

```


[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 render-runtime/react/LayoutContainer.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
// @ts-nocheck
import { LayoutContainer } from 'vtex.render-runtime'

export default LayoutContainer

```


[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 render-runtime/react/ExtensionContainer.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
// @ts-nocheck
import { ExtensionContainer } from 'vtex.render-runtime'

export default ExtensionContainer

```


[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 render-runtime/react/AMP.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import 'react-amphtml'
import 'react-amphtml/helpers'

import {
  AmpScriptsManager,
  AmpScripts,
  headerBoilerplate,
} from 'react-amphtml/setup'
import { RenderRuntime } from './typings/runtime'

export const setupAMP = (
  root: JSX.Element,
  renderFn: any,
  runtime: RenderRuntime
) => {
  const scripts = new AmpScripts()

  const ampRoot = (
    <AmpScriptsManager ampScripts={scripts}>{root}</AmpScriptsManager>
  )

  return {
    ampRoot,
    getExtraRenderedData: () => {
      const ampScripts = renderFn(scripts.getScriptElements())
      const ampHeadBoilerplate = runtime.route.canonicalPath
        ? renderFn(headerBoilerplate(runtime.route.canonicalPath))
        : ''

      return { ampScripts, ampHeadBoilerplate }
    },
  }
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "license": "UNLICENSED",
  "scripts": {
    "lint": "tsc --noEmit --pretty && eslint --fix --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "@formatjs/intl-pluralrules": "^1.3.9",
    "@formatjs/intl-relativetimeformat": "^4.5.1",
    "@sentry/react": "^7.116.0",
    "@vtex/blocks-inspector": "^0.0.8",
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-client": "^2.6.4",
    "apollo-link-error": "^1.1.11",
    "apollo-link-http": "^1.5.15",
    "apollo-link-persisted-queries": "^0.2.2",
    "apollo-upload-client": "^8.1.0",
    "apollo-utilities": "^1.0.16",
    "classnames": "^2.2.5",
    "core-js": "^2.5.7",
    "debounce": "^1.2.0",
    "eventemitter3": "^3.0.0",
    "eventsource-polyfill": "^0.9.6",
    "exenv": "^1.2.2",
    "graphql": "^0.13.2",
    "hoist-non-react-statics": "^2.5.0",
    "js-base64": "^2.4.9",
    "myvtex-sse": "^1.2.0",
    "prop-types": "^15.7.2",
    "query-string": "^5.1.1",
    "ramda": "^0.26.1",
    "react-amphtml": "^4.0.2",
    "react-apollo": "^3.1.2",
    "react-helmet": "^5.2.0",
    "react-json-view": "^1.19.1",
    "route-parser": "^0.0.5",
    "use-media": "^1.4.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "3.1.2",
    "@types/apollo-upload-client": "^8.1.0",
    "@types/debounce": "^1.0.0",
    "@types/eventemitter3": "^2.0.2",
    "@types/graphql": "^0.13.3",
    "@types/history": "^4.7.2",
    "@types/intl": "^1.2.0",
    "@types/jest": "^24.0.0",
    "@types/js-base64": "^2.3.1",
    "@types/node": "^12.12.3",
    "@types/p-queue": "^3.2.1",
    "@types/prop-types": "^15.7.3",
    "@types/qs": "^6.5.1",
    "@types/query-string": "^5.1.0",
    "@types/ramda": "^0.26.36",
    "@types/react": "^16.9.35",
    "@types/react-content-loader": "^3.1.4",
    "@types/react-dom": "^16.8.0",
    "@types/react-helmet": "^5.0.5",
    "@types/react-hot-loader": "^4.1.0",
    "@types/route-parser": "^0.1.1",
    "@vtex/test-tools": "^3.0.0",
    "babel-core": "^6.26.3",
    "babel-jest": "^24.1.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react-app": "^7.0.1",
    "eslint": "^5.16.0",
    "eslint-config-vtex-react": "^5.0.1",
    "eventsource-polyfill": "^0.9.6",
    "history": "^4.7.2",
    "husky": "^1.1.4",
    "jest": "^24.1.0",
    "jest-dom": "^3.1.1",
    "jest-transform-graphql": "^2.1.0",
    "lint-staged": "^8.0.4",
    "prettier": "^2.0.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-hot-loader": "^4.3.12",
    "react-intl": "^3.9.1",
    "react-no-ssr": "^1.1.0",
    "regenerator-runtime": "^0.13.1",
    "ts-jest": "^24.0.1",
    "typescript": "3.9.7"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,css,json,md}": [
      "prettier --write",
      "git add"
    ],
    "*.{ts,tsx}": [
      "eslint --fix",
      "git add"
    ]
  },
  "version": "8.136.1"
}

```


[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 render-runtime/react/error.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* global module */
import React, { Component } from 'react'
import { captureException } from '@sentry/react'

require('myvtex-sse')

const ERROR_PAGE_COMPONENT = 'ErrorPage'

import { renderReadyPromise } from '.'
import { isAdmin } from './utils/isAdmin'
import { CustomAdminTags } from './o11y/types'
import { extractExtra } from './o11y/extractExtra'
import ErrorDisplay from './components/ErrorPage/ErrorPage'

/**
 * The ErrorPage component is rendered when there is an error on the Render Framework server-side lifecycle.
 *
 * Errors that occur on the client-side are caught by the ErrorBoundary component (see react/components/ErrorBoundary.tsx).
 *
 * @warning
 * Updates to this component must be followed by changes to Render Server, specifically the node/middlewares/error.ts file.
 *
 * This is required to ensure that the error page rendered during errors on the server-side lifecycle is always up-to-date, as
 * depending on the error, the Render Server may not be able to fetch the latest version of the ErrorPage component from the
 * Render Runtime, thus falling back to a hardcoded version that must be always up to date.
 *
 * Use this PR as a reference on how to update the Render Server accordingly: https://github.com/vtex/render-server/pull/800.
 */
class ErrorPage extends Component {
  public componentDidMount() {
    if (!isAdmin()) return

    const tags: CustomAdminTags = {
      admin_render_runtime_page: ERROR_PAGE_COMPONENT,
    }

    try {
      const error = window?.__ERROR__
      const requestId = window?.__REQUEST_ID__
      const defaultError =
        'Render Runtime renderered an error page and there is no error or request id available'

      if (error) {
        captureException(error, { tags: { ...tags, ...extractExtra(error) } })
      } else if (requestId) {
        captureException(requestId, { tags })
      } else {
        captureException(defaultError, { tags })
      }
    } catch (e) {
      captureException(e, { tags })
    }
  }

  public render() {
    if (window.__ERROR__) console.error(window.__ERROR__)

    return <ErrorDisplay errorCode={window.__REQUEST_ID__} />
  }
}

if (window.__ERROR__) {
  // compatibility
  window.__RENDER_8_COMPONENTS__ =
    window.__RENDER_8_COMPONENTS__ || global.__RENDER_8_COMPONENTS__
  window.__RENDER_8_HOT__ = window.__RENDER_8_HOT__ || global.__RENDER_8_HOT__
  global.__RUNTIME__ = window.__RUNTIME__
  window.__RENDER_8_COMPONENTS__[ERROR_PAGE_COMPONENT] = ErrorPage as any

  const start = () => {
    global.__RUNTIME__.extensions = global.__RUNTIME__.extensions || {}
    global.__RUNTIME__.pages = global.__RUNTIME__.pages || {}
    global.__RUNTIME__.components = global.__RUNTIME__.components || {}
    global.__RUNTIME__.disableSSR = true
    global.__RUNTIME__.extensions.error = {
      component: ERROR_PAGE_COMPONENT,
      props: {},
    }

    window.__RENDER_8_RUNTIME__.render('error', global.__RUNTIME__)
  }

  renderReadyPromise.then(start)

  if (module.hot) {
    module.hot.accept('./core/main', () => {
      // eslint-disable-next-line @typescript-eslint/no-var-requires
      const hotGlobals = require('./core/main')
      window.__RENDER_8_RUNTIME__.ExtensionContainer =
        hotGlobals.ExtensionContainer
      window.__RENDER_8_RUNTIME__.ExtensionPoint = hotGlobals.ExtensionPoint
      window.__RENDER_8_RUNTIME__.LayoutContainer = hotGlobals.LayoutContainer
      window.__RENDER_8_RUNTIME__.Link = hotGlobals.Link
      window.__RENDER_8_RUNTIME__.Loading = hotGlobals.Loading
      window.__RENDER_8_RUNTIME__.buildCacheLocator =
        hotGlobals.buildCacheLocator
      start()
    })
  } else {
    const CLOSED = 2
    let eventSource: any
    const initSSE = () => {
      const hasNoSSE = !eventSource || eventSource.readyState === CLOSED
      if (!document.hidden && hasNoSSE) {
        eventSource = window.myvtexSSE(
          global.__RUNTIME__.account,
          global.__RUNTIME__.workspace,
          'vtex.builder-hub:*:build.status',
          { verbose: true },
          (event: any) => {
            if (event.body && event.body.code === 'success') {
              window.location.reload()
            }
          }
        )
      }
    }
    initSSE()
    document.addEventListener('visibilitychange', initSSE)
  }
}

```


[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 render-runtime/react/LegacyExtensionContainer.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
// @ts-nocheck
import { LegacyExtensionContainer } from 'vtex.render-runtime'

export default LegacyExtensionContainer

```


[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 render-runtime/react/error.css from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```css

.imgHeight {
  height: 80px;
}

.errorStack {
  margin: 20px auto;
  max-width: 980px;
  word-wrap: 'break-word';
}

.errorDetails {
  font-family: 'courier, code';
  max-width: 980px;
  margin: 20px auto;
  word-wrap: 'break-word';
}

.stringValue {
  word-wrap: 'break-all';
}

@media only screen and (min-width: 40em) {
  .imgHeight {
    height: 225px;
  }
}

```


[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 render-runtime/react/externals.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "commons": {
    "dev": [
      {
        "clientOnly": true,
        "path": "npm:vtex-render-session@1.9.2/dist/index.js"
      },
      {
        "path": "npm:bluebird@3.5.1/js/browser/bluebird.js",
        "serverOnly": true
      },
      {
        "path": "npm:regenerator-runtime@0.11.1/runtime.js"
      },
      {
        "global": "PropTypes",
        "import": "prop-types",
        "path": "npm:prop-types@15.7.2/prop-types.js"
      },
      {
        "global": "React",
        "import": "react",
        "path": "npm:react@16.9.0/umd/react.development.js",
        "alternative": {
          "enableConcurrentMode": "npm:react@0.0.0-experimental-94c0244ba/umd/react.development.js"
        }
      },
      {
        "global": "ReactDOM",
        "import": "react-dom",
        "path": "npm:react-dom@16.9.0/umd/react-dom.development.js",
        "alternative": {
          "enableConcurrentMode": "npm:react-dom@0.0.0-experimental-94c0244ba/umd/react-dom.development.js"
        }
      },
      {
        "global": "ReactDOMServer",
        "import": "react-dom/server",
        "path": "npm:react-dom@16.9.0/umd/react-dom-server.browser.development.js",
        "alternative": {
          "enableConcurrentMode": "npm:react-dom@0.0.0-experimental-94c0244ba/umd/react-dom-server.browser.development.js"
        }
      },
      {
        "global": "ReactIntl",
        "import": "react-intl",
        "path": "npm:react-intl@3.9.1/dist/react-intl.js"
      },
      {
        "global": "History",
        "import": "history",
        "path": "npm:history@4.7.2/umd/history.js"
      },
      {
        "global": "R",
        "import": "ramda",
        "path": "npm:ramda@0.26.1/dist/ramda.js"
      },
      {
        "path": "npm:intl@1.2.5/dist/Intl.js",
        "serverOnly": true
      },
      {
        "clientOnly": true,
        "path": "npm:lazysizes@5.3.2/plugins/unveilhooks/ls.unveilhooks.min.js"
      },
      {
        "clientOnly": true,
        "path": "npm:lazysizes@5.3.2/lazysizes.min.js"
      },
      {
        "clientOnly": true,
        "path": "npm:fg-loadcss@2.1.0/dist/cssrelpreload.min.js"
      },
      {
        "cssRelPreload": true,
        "path": "npm:animate.css@3.7.0/animate.css"
      },
      {
        "path": "npm:vtex-tachyons@3.1.0/tachyons.css"
      },
      {
        "path": "runtime:AMP",
        "serverOnly": true
      },
      {
        "path": "runtime:intl-polyfill",
        "serverOnly": true
      }
    ],
    "prod": [
      {
        "clientOnly": true,
        "path": "npm:vtex-render-session@1.9.2/dist/index.min.js"
      },
      {
        "path": "npm:bluebird@3.5.1/js/browser/bluebird.min.js",
        "serverOnly": true
      },
      {
        "path": "npm:regenerator-runtime@0.11.1/runtime.js"
      },
      {
        "global": "PropTypes",
        "import": "prop-types",
        "path": "npm:prop-types@15.7.2/prop-types.min.js"
      },
      {
        "global": "React",
        "import": "react",
        "path": "npm:react@16.9.0/umd/react.production.min.js",
        "alternative": {
          "enableConcurrentMode": "npm:react@0.0.0-experimental-94c0244ba/umd/react.production.min.js"
        }
      },
      {
        "global": "ReactDOM",
        "import": "react-dom",
        "path": "npm:react-dom@16.9.0/umd/react-dom.production.min.js",
        "alternative": {
          "enableConcurrentMode": "npm:react-dom@0.0.0-experimental-94c0244ba/umd/react-dom.production.min.js"
        }
      },
      {
        "global": "ReactDOMServer",
        "import": "react-dom/server",
        "path": "npm:react-dom@16.9.0/umd/react-dom-server.browser.production.min.js",
        "alternative": {
          "enableConcurrentMode": "npm:react-dom@0.0.0-experimental-94c0244ba/umd/react-dom-server.browser.production.min.js"
        }
      },
      {
        "global": "ReactIntl",
        "import": "react-intl",
        "path": "npm:react-intl@3.9.1/dist/react-intl.min.js"
      },
      {
        "global": "History",
        "import": "history",
        "path": "npm:history@4.7.2/umd/history.min.js"
      },
      {
        "global": "R",
        "import": "ramda",
        "path": "npm:ramda@0.26.1/dist/ramda.min.js"
      },
      {
        "path": "npm:intl@1.2.5/dist/Intl.min.js",
        "serverOnly": true
      },
      {
        "clientOnly": true,
        "path": "npm:lazysizes@5.3.2/plugins/unveilhooks/ls.unveilhooks.min.js"
      },
      {
        "clientOnly": true,
        "path": "npm:lazysizes@5.3.2/lazysizes.min.js"
      },
      {
        "clientOnly": true,
        "path": "npm:fg-loadcss@2.1.0/dist/cssrelpreload.min.js"
      },
      {
        "cssRelPreload": true,
        "path": "npm:animate.css@3.7.0/animate.min.css"
      },
      {
        "path": "npm:vtex-tachyons@3.1.0/tachyons.min.css"
      },
      {
        "path": "runtime:AMP",
        "serverOnly": true
      },
      {
        "path": "runtime:intl-polyfill",
        "serverOnly": true
      }
    ]
  },
  "vtex": {},
  "gocommerce": {}
}

```


[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 render-runtime/react/core/main.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import 'apollo-cache-inmemory'
import 'apollo-client'
import 'apollo-link-http'
import 'apollo-link-persisted-queries'
import 'apollo-upload-client'
import 'apollo-utilities'
import 'classnames'
import 'graphql'
import EventEmitter from 'eventemitter3'
import { createBrowserHistory as createHistory } from 'history'
import queryString from 'query-string'
import React, { ReactElement } from 'react'
import { getDataFromTree } from 'react-apollo'
import {
  hydrate as hydrateDOM,
  render as renderDOM,
  unstable_createRoot,
} from 'react-dom'
import Helmet from '../components/Helmet'
import NoSSR, { useSSR } from '../components/NoSSR'
import { isEmpty } from 'ramda'
import Loading from '../components/Loading'
import {
  MaybeLazyImage,
  LazyImages,
  useLazyImagesContext,
} from '../components/LazyImages'
import { LoadingContextProvider } from '../components/LoadingContext'

import ChildBlock from '../components/ChildBlock'
import useChildBlock from '../components/useChildBlock'
import ExtensionContainer from '../components/ExtensionPoint/ExtensionContainer'
import ExtensionPoint from '../components/ExtensionPoint'
import Block from '../components/Block'
import LayoutContainer from '../components/LayoutContainer'
import LegacyExtensionContainer from '../components/ExtensionPoint/LegacyExtensionContainer'
import Link from '../components/Link'
import RenderContext from '../components/RenderContext'
/** Important: Builder-Hub will only export types of functions imported from individual files.
 * So `useRuntime` should be imported from `../components/useRuntime`
 * and `withRuntimeContext` from `../components/withRuntimeContext` rather than being imported
 * along with the other functions from `RenderContext` */
import useRuntime from '../components/useRuntime'
import withRuntimeContext from '../components/withRuntimeContext'
import canUseDOM from '../components/canUseDOM'
import RenderProvider from '../components/RenderProvider'
import { getVTEXImgHost } from '../utils/assets'
import PageCacheControl from '../utils/cacheControl'
import {
  getState,
  createApolloClient,
  ApolloClientFunctions,
} from '../utils/client'
import { buildCacheLocator } from '../utils/client'
import { getMarkups, getOrCreateContainer } from '../utils/dom'
import { registerEmitter } from '../utils/events'
import { getBaseURI } from '../utils/host'
import registerComponent from '../utils/registerComponent'
import { withSession } from '../utils/session'
import { TreePathContext, useTreePath } from '../utils/treePath'
import {
  isStyleWritable,
  optimizeSrcForVtexImg,
  optimizeStyleForVtexImg,
} from '../utils/vteximg'
import withHMR from '../utils/withHMR'
import { generateExtensions } from '../utils/blocks'
import { promised } from '../utils/promise'
import {
  RenderedSuccess,
  NamedServerRendered,
  Rendered,
  ServerRendered,
} from '../typings/global'
import { RenderRuntime, Extensions } from '../typings/runtime'
// We need to keep this import so the types of this modules are kept in the final bundle by the Builder Hub.
import '../typings/runtime'

let emitter: EventEmitter | null = null
const cssClasses = new Set<string>()

const renderExtension = (
  extensionName: string,
  destination: HTMLElement,
  props = {}
) => {
  if (emitter) {
    emitter.emit('renderExtensionLoader.addOrUpdateExtension', {
      destination,
      extensionName,
      props,
    })
  } else {
    throw new Error(`ExtensionPortal can't be rendered before RenderProvider`)
  }
}

function renderToStringWithData(
  component: ReactElement<any>,
  renderFn: (root: ReactElement) => string,
  skipQuery = false
): Promise<ServerRendered> {
  const getDataFn = (): Promise<string | void> => {
    if (skipQuery) return Promise.resolve()
    return getDataFromTree(component)
  }

  const startGetDataFromTree = window.hrtime()
  return getDataFn().then(() => {
    const endGetDataFromTree = window.hrtime(startGetDataFromTree)

    const startRenderToString = window.hrtime()
    const markup = renderFn(component)
    const endRenderToString = window.hrtime(startRenderToString)
    return {
      markup,
      renderTimeMetric: {
        getDataFromTree: endGetDataFromTree,
        renderToString: endRenderToString,
      },
    }
  })
}

const clientRender = (
  root: JSX.Element,
  elem: Element,
  hydrate: boolean,
  concurrent?: boolean
): Promise<void> => {
  return promised((resolve) => {
    if (concurrent) {
      unstable_createRoot(elem, { hydrate }).render(root)
      resolve()
    } else if (hydrate) {
      hydrateDOM(root, elem, resolve)
    } else {
      renderDOM(root, elem, resolve)
    }
  })
}

const createRootElement = (
  name: string,
  runtime: RenderRuntime,
  sessionPromise: Promise<void>,
  apollo: ApolloClientFunctions
) => {
  const { customRouting, pages, extensions } = runtime
  const isPage =
    !!pages[name] && !!pages[name].path && !!extensions[name]?.component
  const history = canUseDOM && isPage && !customRouting ? createHistory() : null

  return (
    <RenderProvider
      apollo={apollo}
      history={history}
      root={name}
      runtime={runtime}
      sessionPromise={sessionPromise}
    >
      {!isPage ? <ExtensionPoint id={name} /> : null}
    </RenderProvider>
  )
}

const prepareRootElement = (
  name: string,
  runtime: RenderRuntime,
  baseURI: string,
  cacheControl: PageCacheControl | undefined
) => {
  const sessionPromise = canUseDOM
    ? window.__RENDER_8_SESSION__.sessionPromise
    : Promise.resolve()

  return createApolloClient(
    runtime,
    baseURI,
    sessionPromise,
    cacheControl
  ).then((apollo) =>
    apollo
      .hydrate(runtime.queryData)
      .then(() => createRootElement(name, runtime, sessionPromise, apollo))
  )
}

// Either renders the root component to a DOM element or returns a {name, markup} promise.
const render = async (
  name: string,
  runtime: RenderRuntime,
  element?: HTMLElement
): Rendered => {
  const { concurrentMode, disableSSR, disableSSQ, page } = runtime

  const cacheControl = canUseDOM ? undefined : new PageCacheControl()
  const baseURI = getBaseURI(runtime)
  emitter = registerEmitter(runtime, baseURI)

  if (canUseDOM) {
    const { container, created } = element
      ? { container: element, created: false }
      : getOrCreateContainer()
    const shouldHydrate = !(disableSSR || created)
    return promised<void>((resolve) => {
      prepareRootElement(name, runtime, baseURI, cacheControl)
        .then((root) =>
          clientRender(root, container, shouldHydrate, concurrentMode)
        )
        .then(resolve)
    })
  }

  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const { renderToStaticMarkup, renderToString } = require('react-dom/server')

  const commonRenderResult = {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    maxAge: cacheControl!.maxAge,
    page,
  }

  if (runtime.amp) {
    return Promise.all([
      prepareRootElement(name, runtime, baseURI, cacheControl),
      import(
        /* webpackMode: "weak" */
        '../AMP'
      ),
    ]).then(([root, { setupAMP }]) => {
      const { ampRoot, getExtraRenderedData } = setupAMP(
        root,
        renderToStaticMarkup,
        runtime
      )
      return renderToStringWithData(
        ampRoot,
        renderToStaticMarkup,
        disableSSQ
      ).then(({ markup, renderTimeMetric }) => ({
        ...commonRenderResult,
        markups: getMarkups(name, markup),
        renderTimeMetric,
        ...getExtraRenderedData(),
      }))
    })
  }

  return prepareRootElement(name, runtime, baseURI, cacheControl).then((root) =>
    renderToStringWithData(root, renderToString, disableSSQ).then(
      ({ markup, renderTimeMetric }) => ({
        ...commonRenderResult,
        markups: getMarkups(name, markup),
        renderTimeMetric,
      })
    )
  )
}

function validateRootComponent(rootName: string, extensions: Extensions) {
  if (!extensions[rootName]) {
    throw new Error(`Missing extension point for page ${rootName}`)
  }

  if (!extensions[rootName]?.component) {
    throw new Error(`Missing component for extension point ${rootName}`)
  }
}

function setLazyCookie(setCookie: string) {
  if (setCookie) {
    document.cookie = setCookie
  }
}

function start() {
  try {
    if (
      window.__RUNTIME__.blocksTree &&
      !isEmpty(window.__RUNTIME__.blocksTree)
    ) {
      window.__RUNTIME__.hasNewExtensions = true
      window.__RUNTIME__.extensions = generateExtensions(
        window.__RUNTIME__.blocksTree,
        // eslint-disable-next-line
        window.__RUNTIME__.blocks!,
        // eslint-disable-next-line
        window.__RUNTIME__.contentMap!,
        window.__RUNTIME__.pages[window.__RUNTIME__.page]
      )
    }

    if (canUseDOM) {
      const browserQuery = window.location.search
        ? queryString.parse(window.location.search)
        : {}
      const serverQuery = window.__RUNTIME__.serverQuery ?? {}
      window.__RUNTIME__.query = { ...serverQuery, ...browserQuery }
    }

    const runtime: RenderRuntime = window.__RUNTIME__
    runtime.isJanusProxied =
      canUseDOM && window.location.pathname.startsWith('/api/io/')
    const rootName = runtime.page
    validateRootComponent(rootName, runtime.extensions)

    const ReactCreateElement = React.createElement
    const vtexImgHost = getVTEXImgHost(runtime.account)
    React.createElement = function patchedCreateElement(type: any, props: any) {
      if (
        !canUseDOM &&
        typeof type === 'string' &&
        type[0].toLowerCase() === type[0] &&
        props &&
        props.className
      ) {
        const classnames: string[] = props.className.trim().split(/\s+/)
        classnames.forEach((classname) => cssClasses.add(classname))
      }

      if (type === 'a' && props) {
        if (props.target && !props.href) {
          props.target = undefined
        }
        // Follow Google's security recommendations concerning target blank
        // https://developers.google.com/web/tools/lighthouse/audits/noopener
        const rel = props.rel ? props.rel.split(' ') : []
        if (
          props.target === '_blank' &&
          !(rel.indexOf('noopener') !== -1 || rel.indexOf('noreferrer') !== -1)
        ) {
          props.rel = rel.concat('noopener').join(' ')
        }
      }

      if (type === 'img') {
        props.src = optimizeSrcForVtexImg(vtexImgHost, props.src)
        if (
          typeof props.src === 'string' &&
          props.src.startsWith(vtexImgHost)
        ) {
          props.crossOrigin = props.crossOrigin || 'anonymous'
        }
        return ReactCreateElement.apply(React, [
          MaybeLazyImage,
          {
            createElement: ReactCreateElement,
            imageProps: props,
          },
        ])
      }

      if (props && props.style && isStyleWritable(props)) {
        props.style = optimizeStyleForVtexImg(vtexImgHost, props.style)
      }
      // This rule was introduced in a eslint-config update.
      // Should be fixed in a future PR
      //eslint-disable-next-line prefer-rest-params
      return ReactCreateElement.apply(React, arguments)
    }

    const maybeRenderPromise = render(rootName, runtime)
    if (!canUseDOM) {
      // Expose render promise to global context.
      window.rendered = (maybeRenderPromise as Promise<
        NamedServerRendered
      >).then(({ markups, maxAge, page, renderTimeMetric, ...rendered }) => ({
        cssClasses: Array.from(cssClasses).sort(),
        extensions: markups.reduce<RenderedSuccess['extensions']>(
          (acc, { name, markup }) => ((acc[name] = markup), acc),
          {}
        ),
        head: Helmet.rewind(),
        maxAge,
        renderMetrics: { [page]: renderTimeMetric },
        state: getState(runtime),
        ...rendered,
      }))
    } else {
      setLazyCookie(runtime.workspaceCookie)
      maybeRenderPromise
        .then(() => {
          ;(window as any).__HAS_HYDRATED__ = true
        })
        .catch((error) => {
          console.error('Error during hydration', error)
        })
    }
  } catch (error) {
    console.error('Unexpected error rendering:', error)
    if (!canUseDOM) {
      window.rendered = { error }
    }
  }
}

const RenderContextConsumer = RenderContext.Consumer
const TreePathContextConsumer = TreePathContext.Consumer

export {
  ExtensionContainer,
  /** Block is the preferred nomenclature now, ExtensionPoint is kept for
   * backwards compatibility
   */
  Block,
  ExtensionPoint,
  LayoutContainer,
  LegacyExtensionContainer,
  Helmet,
  Link,
  NoSSR,
  useSSR,
  RenderContextConsumer,
  TreePathContextConsumer,
  LazyImages as ExperimentalLazyImages,
  useLazyImagesContext as useExperimentalLazyImagesContext,
  canUseDOM,
  render,
  start,
  withHMR,
  registerComponent,
  withRuntimeContext,
  ChildBlock,
  useChildBlock,
  useRuntime,
  useTreePath,
  withSession,
  Loading,
  LoadingContextProvider,
  buildCacheLocator,
  renderExtension,
  // These unstable APIs should be deprecated shortly
  ChildBlock as Unstable__ChildBlock,
  useChildBlock as useChildBlock__unstable,
}

```


[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 render-runtime/react/typings/render.d.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.render-runtime' {
  let runtimeExports: RuntimeExports
  export = runtimeExports
}

```


[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 render-runtime/react/typings/exenv.d.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'exenv' {
  const canUseDOM: boolean
}

```


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

[User] Show me the implementation of render-runtime/react/typings/runtime.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { IntrospectionResultData } from 'apollo-cache-inmemory'
import EventEmitter from 'eventemitter3'
import { Device, DeviceInfo } from '../utils/withDevice'

export interface RenderRuntime {
  amp: boolean
  account: string
  accountId: string
  appsEtag: string
  binding?: BindingInfo
  blocks?: Blocks
  blocksTree?: BlockContentTree
  channelPrivacy?: 'private' | 'public'
  contentMap?: ContentMap
  customRouting?: boolean
  emitter: EventEmitter
  exposeBindingAddress?: boolean
  workspace: string
  disableSSR: boolean
  disableSSQ: boolean
  hints: RenderHints
  introspectionResult: IntrospectionResultData
  inspect: boolean
  page: string
  route: Route
  version: string
  culture: Culture
  pages: Pages
  extensions: Extensions
  platform: string
  concurrentMode: boolean
  loadedDevices: Device[]
  deviceInfo: DeviceInfo
  preview: boolean
  production: boolean
  publicEndpoint: string
  messages: Record<string, string>
  components: Components
  renderMajor: number
  query?: Record<string, string>
  serverQuery?: Record<string, string>
  start: boolean
  runtimeMeta: {
    version: string
    config?: any
  }
  settings: {
    [app: string]: any
  }
  cacheHints: CacheHintsMap
  segmentToken: string
  defaultExtensions: Extensions
  rootPath?: string
  workspaceCookie: string
  hasNewExtensions: boolean
  queryData?: Array<{
    query: string
    variables: any
    data: string
  }>
  uncriticalStyleRefs?: StyleRefs
  isJanusProxied?: boolean
}

export interface Route {
  domain: string
  blockId: string
  canonicalPath?: string
  id: string
  metaTags?: RouteMetaTags
  pageContext: PageDataContext
  params: Record<string, any>
  queryString?: Record<string, any>
  path: string
  title?: string
}

interface RouteMetaTags {
  description?: string
  keywords?: string[]
}

interface PageDataContext {
  type: string
  id: string
}

interface ContentMap {
  [contentId: string]: Record<string, any>
}

interface RenderHints {
  desktop: boolean
  mobile: boolean
  tablet: boolean
  phone: boolean
  unknown: boolean
}

interface Culture {
  country: string
  availableLocales: string[]
  currency: string
  customCurrencyDecimalDigits: number | null
  customCurrencySymbol: string | null
  language: string
  locale: string
}

export interface Pages {
  [name: string]: Page
}

export interface Page {
  allowConditions: boolean
  canonical?: string
  cname?: string
  path: string
  auth?: boolean
  params?: any
  theme?: string
  disableExternals?: string[]
  declarer?: string | null
  name?: string
  title?: string
  conditional?: boolean
  map?: string[]
  routeId: string
  blockId: string
}

export interface BindingInfo {
  id: string
  canonicalBaseAddress: string
}

type BlockContentTree = Record<string, TreeEntry>
type Blocks = Record<string, BlockEntry>

type RenderStrategy = 'client' | 'lazy' | 'server'
type HydrationType = 'always' | 'on-view'

interface BlockEntry {
  after?: BlockInsertion[]
  around?: BlockInsertion[]
  before?: BlockInsertion[]
  blockId: string
  blocks?: BlockInsertion[]
  component: string
  composition?: Composition
  hasContentSchema: boolean
  props?: Record<string, any>
  context?: {
    component: string
    props?: Record<string, any>
  }
  implements: string[]
  originalBlockId?: string
  preview?: Preview
  render: RenderStrategy
  hydration?: HydrationType
  track?: string[]
  title?: string
}

interface TreeEntry {
  blockIdMap: Record<string, string>
  contentIdMap: Record<string, string>
}

export interface BlockInsertion {
  extensionPointId: string
  blockId: string
  /**
   * This property was replaced by blockRole,
   * but it cannot be removed since that would be a breaking-change
   * in builder-hub. Prefer using blockRole since it can tell you more
   * about the BlockInsertion.
   */
  children?: boolean
  blockRole?: 'block' | 'children' | 'slot'
}

export interface Extension {
  after?: string[]
  around?: string[]
  before?: string[]
  blockId?: string
  blocks?: BlockInsertion[]
  context?: {
    component: string
    props?: any
  }
  component: string
  track?: string[]
  props?: any
  content?: Record<string, any>
  render?: RenderStrategy
  preview?: Preview
  hydration?: HydrationType
  composition?: Composition
  hasContentSchema?: boolean
  contentIds?: string[]
}

export interface Extensions {
  [name: string]: Extension
}

enum Composition {
  blocks = 'blocks',
  children = 'children',
}

interface Preview {
  type: string
  width: PreviewDimension
  height: PreviewDimension
  fullWidth?: boolean
  options?: any
}

export interface PreviewDimension {
  desktop: PreviewDimensionValue
  mobile: PreviewDimensionValue
}

interface PreviewDimensionValue {
  fromProp?: string
  defaultValue?: number
}

interface StyleRefs {
  base: StyleRef[]
  overrides: StyleRef[]
}

export interface StyleRef {
  path: string
  id?: string
  class?: string
  crossorigin?: boolean
  preload?: boolean
  media?: string
}

export interface CacheHints {
  scope?: string
  maxAge?: string
  version?: number
  provider?: string
  sender?: string
}

interface CacheHintsMap {
  [hash: string]: CacheHints
}

export interface Components {
  [entrypoint: string]: ComponentEntry
}

interface ComponentEntry {
  assets: string[]
  dependencies: string[]
}

// We need to keep this so this file is kept in type generation
export default {}

```


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

[Assistant]
Here's the implementation:

```typescript
import { ApolloClient } from 'apollo-client'
import { NormalizedCacheObject } from 'apollo-cache-inmemory'
import { EventEmitter } from 'eventemitter3'
import { Component } from 'react'
import ExtensionContainer from '../ExtensionContainer'
import ExtensionPoint from '../components/ExtensionPoint/index'
import Link from '../components/Link'
import { History, Location } from 'history'
import { HelmetData } from 'react-helmet'
import { TreePathProps } from '../utils/treePath'

import type { RenderContext } from '../components/RenderContext'

interface RenderMetric {
  getDataFromTree?: [number, number]
  renderToString: [number, number]
}

interface ServerRendered {
  markup: string
  renderTimeMetric: RenderMetric
}

interface NamedMarkup {
  markup: string
  name: string
}

interface NamedServerRendered {
  markups: NamedMarkup[]
  maxAge: number
  page: string
  renderTimeMetric: RenderMetric
  ampScripts?: string[]
}

type ClientRendered = Element

interface LogEvent {
  name: string
  data?: any
}

interface NavigationRoute {
  path: string
  params: Record<string, any>
  id: string
}

interface SetQueryOptions {
  merge?: boolean
  replace?: boolean
  scrollOptions?: RenderScrollOptions
}

interface RelativeScrollToOptions extends ScrollToOptions {
  baseElementId?: string
}

type RenderScrollOptions = RelativeScrollToOptions | false

interface RenderHistoryLocation extends Location {
  state?: {
    navigationRoute: NavigationRoute
    renderRouting?: true
    scrollOptions?: RenderScrollOptions
    fetchPage?: boolean
    preventRemount?: boolean
  }
}

interface RenderedSuccess {
  state: any
  head: HelmetData
  maxAge: number
  extensions: {
    [id: string]: string
  }
  renderMetrics: {
    [name: string]: RenderMetric
  }
}

interface RenderedFailure {
  error: any
}

type ConfigurationDevice = 'any' | 'desktop' | 'mobile'

interface PageContextOptions {
  scope?: string
  device?: string
  conditions?: string[]
  template?: string
}

export type ApolloClientType = ApolloClient<NormalizedCacheObject>

interface FetchRoutesInput extends PageContextOptions {
  apolloClient: ApolloClientType
  locale: string
  page: string
  paramsJSON?: string
  path?: string
  production: boolean
  renderMajor: number
}

interface FetchDefaultPages {
  apolloClient: ApolloClientType
  locale: string
  pages: Pages
  routeIds: string[]
  renderMajor: number
}

interface FetchNavigationDataInput {
  apolloClient: ApolloClientType
  production: boolean
  locale: string
  routeId: string
  declarer?: string | null
  paramsJSON?: string
  path?: string
  renderMajor: number
  skipCache: boolean
  query?: string
}

interface RenderComponent<P = {}, S = {}> {
  getCustomMessages?: (locale: string) => any
  WrappedComponent?: RenderComponent
  new (): Component<P, S>
}

interface ComponentsRegistry {
  [component: string]: RenderComponent<any, any>
}

interface HotEmitterRegistry {
  [appId: string]: EventEmitter
}

interface GraphQLResult<T extends string, U> {
  data: Record<T, U>
  errors?: any
}

interface DefaultPagesQueryResult {
  data: DefaultPagesQueryResultData
  errors?: any
}

interface DefaultPagesQueryResultData {
  defaultPages: DefaultPagesQueryResponse
}

interface MatchingPage {
  blockId: string
  canonicalPath?: string
  metaTags?: RouteMetaTags
  pageContext: PageDataContext
  title?: string
  routeId: string
}

type Rendered = Promise<void | ClientRendered | NamedServerRendered>

interface MatchingServerPage {
  blockId: string
  canonicalPath?: string
  metaTags?: RouteMetaTags
  pageContext: PageDataContext
  title?: string
  routeId: string
  params: Record<string, string>
  queryString?: Record<string, any>
  id: string
  path: string
  domain: string
}

interface ServerPageResponse {
  appsEtag: RenderRuntime['appsEtag']
  blocks: RenderRuntime['blocks']
  blocksTree: RenderRuntime['blocksTree']
  cacheHints: RenderRuntime['cacheHints']
  contentMap: RenderRuntime['contentMap']
  components: RenderRuntime['components']
  extensions: RenderRuntime['extensions']
  messages: RenderRuntime['messages']
  pages: RenderRuntime['pages']
  route: MatchingServerPage
  settings: RenderRuntime['settings']
  queryData: RenderRuntime['queryData']
  page: string
}

interface PageQueryResponse {
  blocksJSON: string
  blocksTreeJSON: string
  contentMapJSON: string
  componentsJSON: string
  extensionsJSON: string
  messages: KeyedString[]
  pagesJSON: string
  appsSettingsJSON: string
  appsEtag: string
  cacheHintsJSON: string
  page: MatchingPage
}

interface DefaultPagesQueryResponse {
  componentsJSON: string
  extensionsJSON: string
  messages: KeyedString[]
}

interface KeyedString {
  key: string
  message: string
}

interface ParsedServerPageResponse extends ServerPageResponse {
  matchingPage: MatchingServerPage
}

interface ParsedPageQueryResponse {
  blocks: RenderRuntime['blocks']
  blocksTree: RenderRuntime['blocksTree']
  contentMap: RenderRuntime['contentMap']
  components: RenderRuntime['components']
  extensions: RenderRuntime['extensions']
  messages: RenderRuntime['messages']
  pages: RenderRuntime['pages']
  appsEtag: RenderRuntime['appsEtag']
  settings: RenderRuntime['settings']
  cacheHints: RenderRuntime['cacheHints']
  matchingPage: MatchingPage
}

interface ParsedDefaultPagesQueryResponse {
  components: RenderRuntime['components']
}

type Rendered = Promise<ClientRendered | NamedServerRendered>

interface AssetEntry {
  name: string
  path: string
  app: string
}

interface RuntimeExports {
  ExtensionContainer: ExtensionContainer
  ExtensionPoint: ExtensionPoint
  Link: Link
  NoSSR: any
  LayoutContainer: any
  LegacyExtensionContainer: any
  Loading: any
  Helmet: any
  canUseDOM: boolean
  withHMR: any
  withRuntimeContext: any
  withSession: any
  RenderContextConsumer: React.Consumer<RenderContext>
  TreePathContextConsumer: React.Consumer<TreePathProps>
  buildCacheLocator: any
  useRuntime(): RenderContext
  start(): void
  render(name: string, runtime: RenderRuntime, element?: HTMLElement): Rendered
}

interface RenderSession {
  patchSession: (data: any) => Promise<void>
  sessionPromise: Promise<void>
}

declare global {
  interface Window extends Window {
    __APP_ID__: string
    __ERROR__: any
    __hasPortals__: boolean
    __hostname__: string
    __pathname__: string
    __provideRuntime: (
      runtime: RenderContext | null,
      messages: Record<string, string>,
      shouldUpdateRuntime: boolean,
      setMessages: (messages: RenderRuntime['messages']) => void
    ) => Promise<void>
    __RENDER_8_COMPONENTS__: ComponentsRegistry
    __RENDER_8_HOT__: HotEmitterRegistry
    __RENDER_8_RUNTIME__: RuntimeExports
    __RENDER_8_SESSION__: RenderSession
    __REQUEST_ID__: string
    __RUNTIME__: RenderRuntime
    __RUNTIME_EXTENSIONS__: RenderRuntime['extensions']
    __RUNTIME_QUERYDATA__: RenderRuntime['queryData']
    __STATE__: NormalizedCacheObject
    __DOM_READY__?: boolean
    __ASYNC_SCRIPTS_READY__?: boolean
    __CRITICAL__UNCRITICAL_APPLIED__: Promise<void> | undefined
    __CRITICAL__RAISE_UNCRITICAL_EVENT__: () => void | null
    browserHistory: History
    flags: Record<string, boolean>
    hrtime: NodeJS.Process['hrtime']
    Intl: any
    IntlPolyfill: any
    myvtexSSE: any
    ReactAMPHTML: any
    ReactAMPHTMLHelpers: any
    ReactIntlLocaleData: any
    ReactIntl: any
    IntlPluralRules: any
    IntlRelativeTimeFormat: any
    rendered: Promise<RenderedSuccess> | RenderedFailure
    requestIdleCallback: (callback: (...args) => any | void) => number
    ReactApollo: any
  }

  namespace NodeJS {
    interface Global extends Window {
      myvtexSSE: any
    }
  }

  interface NodeModule {
    hot: any
  }
}

interface PrefetchRouteData {
  extensions: RenderRuntime['extensions']
  components: RenderRuntime['components']
  messages: RenderRuntime['messages']
}

interface ContentResponse {
  contentMapJSON: string
  extensionsContent: {
    contentJSON: string
    contentIds: string[]
    treePath: string
  }[]
  contentMessages: RenderRuntime['messages']
}

```


[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 render-runtime/react/typings/node.d.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Module {
  hot: any
}

declare const module: Module

declare module '*.graphql' {
  import { DocumentNode } from 'graphql'

  const value: DocumentNode
  export default value
}

declare module '*.png' {
  let url: string
  export = url
}

declare module '*.css' {
  const content: any
  export default content
}

declare const vtex: any

```


[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 render-runtime/react/queries/navigationPage.graphql from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```graphql
query NavigationPage (
  $routeId: String,
  $declarer: String,
  $params: String,
  $path: String,
  $query: String,
  $renderMajor: Int,
) {
  navigationPage(
    routeId: $routeId,
    declarer: $declarer,
    params: $params,
    path: $path,
    query: $query,
    renderMajor: $renderMajor
  ) {
    appsEtag
    appsSettingsJSON
    blocksJSON
    blocksTreeJSON
    contentMapJSON
    cacheHintsJSON
    componentsJSON
    extensionsJSON
    messages {
      key
      message
    }
    page {
      blockId
      canonicalPath
      metaTags {
        description
        keywords
      }
      pageContext {
        id
        type
      }
      title
      routeId
    }
    pagesJSON
  }
}

```


[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 render-runtime/react/queries/routeData.graphql from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```graphql
query RouteData($routeId: String, $declarer: String, $query: String, $device: UserDevice, $renderMajor: Int) {
  prefetchBlocks(input:{ routeId:$routeId, renderMajor:$renderMajor, declarer: $declarer, query: $query, device: $device}) {
    extensionsJSON
    componentsJSON
    messages {
      key
      message
    }
  }
}

```


[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 render-runtime/react/queries/routePreviews.graphql from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```graphql
query RoutePreviews($routes: [PreviewRouteInput], $renderMajor: Int) {
  defaultPages: routePreviews (
    routes: $routes,
    renderMajor: $renderMajor,
  ) {
    componentsJSON
  }
}

```


[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 render-runtime/react/queries/ListContent.graphql from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```graphql
query ListContent(
  $bindingId: String
  $blockId: String
  $pageContext: PageContextInput
  $template: String
  $treePath: String
) {
  listContent(
    bindingId: $bindingId
    blockId: $blockId
    pageContext: $pageContext
    template: $template
    treePath: $treePath
  ) {
    contentJSON
  }
}

```


[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 render-runtime/react/start/styles.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { canUseDOM } from 'exenv'

export const hydrateUncriticalStyles = async () => {
  if (
    canUseDOM &&
    typeof window.__CRITICAL__RAISE_UNCRITICAL_EVENT__ === 'function'
  ) {
    window.__CRITICAL__RAISE_UNCRITICAL_EVENT__()
    return window.__CRITICAL__UNCRITICAL_APPLIED__
  }
}

```


[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 render-runtime/react/start/runtime.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { promised } from '../utils/promise'

const getValue = (element: HTMLTemplateElement) => {
  if (typeof element.content === 'undefined') {
    return element.textContent as string
  }

  // Using textContent instead of innerHTML because it's faster
  let value = ''
  const childNodes = element.content.childNodes
  for (let i = 0; i < childNodes.length; i++) {
    const node = childNodes[i]
    value += node.textContent
  }
  return value
}

const writeVarToWindow = (template: HTMLTemplateElement, value: string) => {
  const { varname, field } = template.dataset
  const windowAsAny = window as any
  if (!varname) {
    console.error('Missing data-varname:', template)
    return
  }

  if (!field) {
    windowAsAny[varname] = JSON.parse(value)
    return
  }

  if (!windowAsAny[varname]) {
    console.error(`Global var ${varname} not found to set ${field}`)
  }

  windowAsAny[varname][field] = JSON.parse(value)
}

export const loadRuntimeJSONs = (): Promise<void | void[]> => {
  const templates = window?.document?.querySelectorAll<HTMLTemplateElement>(
    'template[data-type="json"]'
  )
  if (!templates || templates.length === 0) {
    return Promise.resolve()
  }

  const promises = Array.from(templates).map((template) =>
    promised<string>((resolve) => {
      const value = getValue(template)
      resolve(value)
    }).then((value) =>
      promised<void>((resolve) => {
        writeVarToWindow(template, value)
        resolve()
      })
    )
  )

  return Promise.all(promises)
}

```


[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 render-runtime/react/start/amp.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { canUseDOM } from 'exenv'
import { RenderRuntime } from '../typings/runtime'

export const addAMPProxy = (runtime: RenderRuntime) => {
  if (!runtime.amp) {
    window.ReactAMPHTML = window.ReactAMPHTMLHelpers =
      typeof Proxy !== 'undefined'
        ? new Proxy(
            {},
            {
              get: (_, key) => {
                if (key === '__esModule' || key === 'constructor') {
                  return
                }
                const message = canUseDOM
                  ? 'You can not render AMP components on client-side'
                  : 'You must check runtime.amp to render AMP components'

                throw new Error(message)
              },
            }
          )
        : {} // IE11 users will not have a clear error in this case
  }
}

```


[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 render-runtime/react/start/register.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const registerRuntimeGlobals = (runtimeGlobals: any) => {
  window.__RENDER_8_RUNTIME__ = { ...runtimeGlobals }

  // compatibility
  window.__RENDER_8_COMPONENTS__ =
    window.__RENDER_8_COMPONENTS__ || global.__RENDER_8_COMPONENTS__
  window.__RENDER_8_HOT__ = window.__RENDER_8_HOT__ || global.__RENDER_8_HOT__
}

```


[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 render-runtime/react/start/patchLibs.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { createCustomReactApollo } from '../utils/reactApollo'
import { createReactIntl } from '../utils/reactIntl'

export const patchLibs = () => {
  if (window.ReactApollo) {
    window.ReactApollo = createCustomReactApollo()
  }

  if (window.ReactIntl) {
    window.ReactIntl = createReactIntl()
  }
}

```


[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 render-runtime/react/start/intl.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { canUseDOM } from 'exenv'
import { prop } from 'ramda'

export const polyfillIntl = () => {
  if (window.IntlPolyfill) {
    window.IntlPolyfill.__disableRegExpRestore()
    if (!window.Intl) {
      window.Intl = window.IntlPolyfill
    }
  }

  if (
    window.Intl &&
    canUseDOM &&
    (!window.Intl.PluralRules || !window.Intl.RelativeTimeFormat)
  ) {
    return import('../intl-polyfill').then(prop('default'))
  }

  return Promise.resolve()
}

```