[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 store-graphql/graphql/types/Payment.graphql from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type PaymentSession {
    id: String
    name: String
    expiresAt: String
}

type PaymentToken {
    token: String
    bin: String
    lastDigits: String
    expiresAt: String
    paymentSystem: String
    paymentSystemName: String
}

""" Payment data used by profile resolvers """
type PaymentProfile {
    """ Id representing this payment form used as reference for the cache"""
    cacheId: ID
    """ Id representing this payment form"""
    id: String
    """ Id for the payment system related to this payment form"""
    paymentSystem: String
    """ The name of the payment system """
    paymentSystemName: String
    """ Last digits of the card this type represents (in the form ************9999)"""
    cardNumber: String
    """ Billing address for this payment form (type definition in the Profile file)"""
    address: Address
    """ Boolean informing whether the card is expired or not """
    isExpired: Boolean
    """ String representing the expiration date in the form dd/yyyy """
    expirationDate: String
    """ Flag indicating if the card was registered in Profile System as 'notFound' or 'billingAddressEmpty' on the Gateway side """
    accountStatus: String
}

input PaymentInput {
    paymentSystem: String
    cardHolder: String
    cardNumber: String
    expiryDate: String
    csc: String
    document: String
    documentType: String
    partnerId: String
    address: PaymentAddress
}

input PaymentAddress {
    postalCode: String
    street: String
    neighborhood: String
    city: String
    receiverName: String
    state: String
    country: String
    number: String
    complement: String
  }

```


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

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

[Assistant]
Here's the implementation:

```graphql
input PlaceholderInput {
  name: String
  component: String
  settings: String
}

```


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

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

[Assistant]
Here's the implementation:

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

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


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

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

[Assistant]
Here's the implementation:

```graphql
type Search {
  facets: Facets
  products: [Product]
  recordsFiltered: Int
  titleTag: String
  metaTagDescription: String
}

```


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

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

[Assistant]
Here's the implementation:

```graphql
type SearchContext {
  contextKey: String
  brand: String
  category: String
}

```


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

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

[Assistant]
Here's the implementation:

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

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

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

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

type AssemblyOption {
  id: ID
  name: String @translatableV2
  required: Boolean
  composition: CompositionType
}

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

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

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

```


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

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

[Assistant]
Here's the implementation:

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

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

```


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

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

[Assistant]
Here's the implementation:

```graphql
type LoginOptions {
  """ List of Social providers """
  providers: [Provider],
  """ Email and Password authentication """
  classicAuthentication: Boolean,
  """ Access key through email Code verification """
  accessKeyAuthentication: Boolean
}

""" Describes an OAuth provider type. e.g.: Google, Facebook"""
type Provider {
  """ Provider Name. e.g.: Google, Facebook """
  providerName: String,
  """ The provider class. e.g.: google-plus, facebook """
  className: String
}
```


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

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

[Assistant]
Here's the implementation:

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

```


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

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

[Assistant]
Here's the implementation:

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

type OnlyProduct {
  brand: String
  categoryId: ID
  categories: [String]
    @deprecated(
      reason: "Use 'categoryTree' field for internationalization support"
    )
  categoriesIds: [String]
    @deprecated(
      reason: "Use 'categoryTree' field for internationalization support"
    )
  categoryTree: [Category]
  clusterHighlights: [ClusterHighlight]
  productClusters: [ProductClusters]
  description: String
  link: String
  linkText: String
  productId: ID
  productName: String
  properties: [Property]
  propertyGroups: [PropertyGroup]
  productReference: String
  recommendations: Recommendation
  jsonSpecifications: String
}

type ProductClusters {
  id: ID
  name: String
}

type ClusterHighlight {
  id: ID
  name: String
}

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

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

type SKU {
  itemId: ID
  name: String @translatableV2
  nameComplete: String @translatableV2
  complementName: String
  ean: String
  referenceId: [Reference]
  measurementUnit: String
  unitMultiplier: Float
  kitItems: [KitItem]
  images(quantity: Int = 10): [Image]
  videos: [Video]
  sellers: [Seller]
  variations: [Property]
  attachments: [Attachment]
  calculatedAttachments: String
  productName: String @translatableV2
  productDescription: String @translatableV2
  brandName: String @translatableV2
  skuSpecifications: [skuSpecification]
  productSpecifications: [productSpecification]
}

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

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

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

enum ProductUniqueIdentifierField {
  id
  slug
  ean
  reference
  sku
}

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

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

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

enum InstallmentsCriteria {
  MAX
  MIN
  ALL
}

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

type Parameter {
  name: String
  value: String
}

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

type TeaserEffect {
  parameters: [Parameter]
}

type GeneralValueTeaser {
  key: String
  value: String
}

type AdditionalInfo {
  key: String
  value: String
}

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

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

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

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

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

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

type Video {
  videoUrl: String
}

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

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

type Property {
  name: String
  values: [String]
}

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

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

type Reference {
  Key: String
  Value: String
}

enum CrossSelingInputEnum {
  buy
  similars
  view
  viewAndBought
  accessories
  suggestions
}

input ItemInput {
  itemId: ID
  sellers: [SellerInput]
}

input SellerInput {
  sellerId: ID
}

```


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

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

[Assistant]
Here's the implementation:

```graphql
""" List of Products """
type List {
    """ List's id """
    id: ID
    """ The list's name """
    name: String
    """ Flag that indicates if the list is public or not """
    isPublic: Boolean
    """ Flag that indicates if the list is editable or not """
    isEditable: Boolean
    """ List's owner """
    owner: String
    """ Creation date """
    createdIn: String
    """ Update date """
    updatedIn: String
    """ List items """
    items: [ListItem]
}
type ListItem {
    """ Item id """
    id: ID
    """ Product id """
    productId: ID
    """ Sku id """
    skuId: ID
    """ The quantity of the item """
    quantity: Int
    """ The product's informations """
    product: Product
    """ Date when it was added """
    createdIn: String
}

input ListInput {
    """ The list's name """
    name: String!
    """ Flag that indicates if the list is public or not """
    isPublic: Boolean
    """ Flag that indicates if the list is editable or not """
    isEditable: Boolean
    """ List's owner """
    owner: String
    """ List items """
    items: [ListItemInput]
}

input ListItemInput {
    """ List item id """
    id: ID
    """ Product id """
    productId: ID!
    """ Sku id """
    skuId: ID!
    """ The quantity of the item """
    quantity: Int
}
```


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

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

[Assistant]
Here's the implementation:

```graphql
"""
Informations about user Session
"""
type Session {
  cacheId: ID
  """
  Session ID
  """
  id: ID
  """
  Id of admin logged in session
  """
  adminUserId: String
  """
  Email of Admin logged in session
  """
  adminUserEmail: String
  """
  Check if this admin can impersonate a user
  """
  impersonable: Boolean
  """
  Object with information about impersonate user
  """
  impersonate: ImpersonatedUser
  """
  Customer address
  """
  address: Address
  """
  Profile information of session user
  """
  profile: SessionProfile
  """
  UTM Params
  """
  utmParams: UTMParams
  """
  UTMI Params
  """
  utmiParams: UTMIParams
  favoritePickup: SessionPickup
}

"""
Basic information that is displayed when is a impersonated session
"""
type ImpersonatedUser {
  """
  Profile information of impersonated user
  """
  profile: SessionProfile
}

type UTMParams {
  source: String
  medium: String
  campaign: String
  term: String
  content: String
}

type UTMIParams {
  campaign: String
  page: String
  part: String
}

type SessionPickup {
  cacheId: ID
  name: String
  address: Address
}

```


[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 store-graphql/graphql/types/Shipping.graphql from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type ShippingData {
  items: [LogisticsItem]
  logisticsInfo: [LogisticsInfo]
  messages: [MessageInfo]
}

type MessageInfo {
  code: String
  text: String
  status: String
  fields: MessageFields
}

type MessageFields {
  itemIndex: String
  ean: String
  skuName: String
}

type LogisticsInfo {
  itemIndex: String
  selectedSla: String
  slas: [ShippingSLA]
}

type ShippingSLA {
  id: String
  name: String
  price: Float
  shippingEstimate: String
  shippingEstimateDate: String
  deliveryIds: [DeliveryIds]
  deliveryChannel: String
  friendlyName: String
  pickupPointId: String
  pickupStoreInfo: pickupStoreInfo
  pickupDistance: Float
}

type pickupStoreInfo {
  friendlyName: String
  address: PickupAddress
  additionalInfo: String
  dockId: String
  isPickupStore: Boolean
}

type PickupAddress {
  addressType: String
  receiverName: String
  addressId: String
  postalCode: String
  city: String
  state: String
  country: String
  street: String
  number: String
  neighborhood: String
  complement: String
  reference: String
  geoCoordinates: [Float]
}

type DeliveryIds {
  courierId: String
  warehouseId: String
  dockId: String
  courierName: String
  quantity: Int
}

type LogisticsItem {
  id: String
  requestIndex: Int
  quantity: Int
  seller: String
  sellerChain: [String]
  tax: Int
  priceValidUntil: String
  price: Int
  listPrice: Int
  rewardValue: Int
  sellingPrice: Int
  measurementUnit: String
  unitMultiplier: Float
  availability: String
}

input ShippingItem {
  id: String
  quantity: String
  seller: String
}

```


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

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

[Assistant]
Here's the implementation:

```graphql
enum DeviceType {
  MOBILE
  TABLET
  DESKTOP
}

type LoginSession {
  id: ID!
  cacheId: ID!
  deviceType: DeviceType!
  city: String
  lastAccess: String!
  browser: String
  os: String
  ip: String
  fullAddress: String
  firstAccess: String!
}

type LoginSessionsInfo {
  currentLoginSessionId: ID
  loginSessions: [LoginSession!]
}

```


[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 store-graphql/graphql/types/Logistics.graphql from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type LogisticsData {
  """
  Countries this store ships to
  """
  shipsTo: [String]
  """
  Google Maps Geolocation API key
  """
  googleMapsKey: String
}

type PickupPoint {
  """
  Working hours of given pickup point
  """
  businessHours: [BusinessHours]
  """
  If false, it means pickup point is currently disabled
  """
  isActive: Boolean
  """
  Pickup point restrictions
  """
  pickupHolidays: [HolidayHours]
  """
  Distance in kilometers if this is a search result
  """
  distance: Float
  friendlyName: String
  id: String
  """
  AdditionalInfo from pickup point
  """
  instructions: String
  """
  Seller account name
  """
  seller: String
  address: Address
}

type BusinessHours {
  """
  Opening time in format HH:MM:SS
  """
  openingTime: String
  """
  Day of the week representation, 0 for Sunday, 1 for Monday...
  """
  dayOfWeek: Int
  """
  Closing time in format HH:MM:SS
  """
  closingTime: String
}

type HolidayHours {
  """
  date time in format HH:MM:SS
  """
  date: String
  """
  hourBegin time in format HH:MM:SS
  """
  hourBegin: String
  """
  hourEnd time in format HH:MM:SS
  """
  hourEnd: String
}

type NearPickupPointQueryResponse {
  """
  List of pickup points found
  """
  items: [PickupPoint]
}

```


[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 store-graphql/node/directives/withOwnerId.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defaultFieldResolver, GraphQLField } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'

import { getOwnerIdFromCookie } from '../utils'

export class WithOwnerId extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root: any, args: any, ctx: Context, info: any) => {
      const checkoutOwnerId = getOwnerIdFromCookie(ctx.cookies)

      ctx.vtex.ownerId = checkoutOwnerId

      return resolve(root, args, ctx, info)
    }
  }
}

```


[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 store-graphql/node/directives/authorizationMetrics.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defaultFieldResolver, GraphQLField, GraphQLResolveInfo } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'

function checkForAuthorization(ctx: any, info: GraphQLResolveInfo) {
  const {
    request: {
      headers: {
        'user-agent': userAgent,
        'x-forwarded-for': forwardedFor,
        'x-forwarded-host': forwardedHost,
        'x-forwarded-path': forwardedPath,
        'x-vtex-caller': vtexCaller,
        origin,
        Authorization,
      },
    },
    vtex: { logger, adminUserAuthToken, storeUserAuthToken },
  } = ctx

  const vtexIdToken =
    ctx.cookies.get('VtexIdclientAutCookie') ?? ctx.get('VtexIdclientAutCookie')

  if (!vtexIdToken && Math.floor(Math.random() * 100) === 0) {
    logger.warn({
      message: 'Private route being accessed by unauthorized user',
      userAgent,
      forwardedFor,
      forwardedHost,
      forwardedPath,
      origin,
      vtexCaller,
      Authorization,
      adminUserAuthToken,
      storeUserAuthToken,
      queryName: info?.fieldName,
      queryParentType: info?.parentType.name,
      queryReturnType: info?.returnType.toString(),
    })
  }
}

export class AuthorizationMetrics extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root, args, ctx, info) => {
      checkForAuthorization(ctx, info)

      return resolve(root, args, ctx, info)
    }
  }
}

```


[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 store-graphql/node/directives/withSegment.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defaultFieldResolver, GraphQLField } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'
import atob from 'atob'

/**
 * Warning: we stopped using the segment client to decode the segment token for us because it added unnecessary overhead for now.
 * If the getSegment API evolves to do more than a decode we must stop decoding it here and start calling the API once again.
 */
export class WithSegment extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root, args, ctx: Context, info) => {
      const {
        vtex: { segmentToken },
        clients: { segment },
      } = ctx

      ctx.vtex.segment = segmentToken
        ? JSON.parse(atob(segmentToken))
        : await segment.getSegment()

      return resolve(root, args, ctx, info)
    }
  }
}

```


[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 store-graphql/node/directives/withCurrentProfile.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { parse as parseCookie } from 'cookie'
import { defaultFieldResolver, GraphQLField, GraphQLResolveInfo } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'
import jwtDecode from 'jwt-decode'
import { AuthenticationError, ResolverError } from '@vtex/api'

import { getSession } from '../resolvers/session/service'
import { SessionFields } from '../resolvers/session/sessionResolver'
import { DefaultUser, User } from '../dataSources/identity'

type UserType = 'StoreUser' | 'CallCenterOperator'
interface ProfileInfos<ProfileType = CurrentProfile | null> {
  currentProfile: ProfileType
  userType?: UserType
  userData?: User | DefaultUser
}

export class WithCurrentProfile extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root, args, context, info) => {
      const profileInfos: ProfileInfos = await getCurrentProfileFromSession(
        context
      )
        .catch(() => {
          if (context.vtex.storeUserAuthToken) {
            return getStoreUserProfileFromCookie(context)
          }

          return getCurrentProfileFromCookies(context)
        })
        .catch(() => ({
          currentProfile: null,
        }))

      const { currentProfile } = profileInfos

      if (!isLogged(currentProfile)) {
        return null
      }

      // If the current profile doesn't exist, a new profile will be created, there is no need to check it
      if (profileInfos.currentProfile !== null) {
        await checkUserAccount(
          context,
          profileInfos as ProfileInfos<CurrentProfile>,
          info
        )
      }

      context.vtex.currentProfile = await validatedProfile(
        context,
        currentProfile as CurrentProfile
      )

      return resolve(root, args, context, info)
    }
  }
}

async function getCurrentProfileFromSession(
  context: Context
): Promise<ProfileInfos> {
  return getSession(context).then((currentSession) => {
    const session = currentSession as SessionFields

    if (!session || !session.id) {
      throw new ResolverError('Error fetching session data')
    }

    const profile = session?.impersonate?.profile ?? session.profile

    return {
      currentProfile: profile
        ? ({ email: profile.email, userId: profile.id } as CurrentProfile)
        : null,
      // If is impersonate is a call center op
      userType:
        session?.impersonate?.profile || session?.public?.impersonate
          ? 'CallCenterOperator'
          : 'StoreUser',
    }
  })
}

async function getStoreUserProfileFromCookie(
  context: Context
): Promise<ProfileInfos> {
  const {
    vtex: { storeUserAuthToken: userToken },
    dataSources: { identity },
  } = context

  return identity.getUserWithToken(userToken!).then((data) => {
    if (data && 'id' in data) {
      return {
        currentProfile: { userId: data.id, email: data.user },
        userData: data,
        userType: 'StoreUser',
      }
    }

    return { currentProfile: null }
  })
}

async function getCurrentProfileFromCookies(
  context: Context
): Promise<ProfileInfos> {
  const {
    clients: { profile },
    vtex: { adminUserAuthToken, storeUserAuthToken },
    request: {
      headers: { cookie },
    },
  } = context

  const parsedCookies = parseCookie(cookie || '')

  const userToken = storeUserAuthToken
  const adminToken = adminUserAuthToken

  if (!userToken && !!adminToken) {
    const adminInfo = jwtDecode(adminToken) as any

    const callOpUserEmail = adminInfo?.sub
    const isValidCallOp =
      callOpUserEmail &&
      (await isValidCallcenterOperator(context, callOpUserEmail))

    if (!isValidCallOp) {
      throw new AuthenticationError('User is not a valid callcenter operator')
    }

    const customerEmail = parsedCookies['vtex-impersonated-customer-email']

    return profile
      .getProfileInfo({ email: customerEmail, userId: '' }, context, undefined)
      .then(({ email, userId }) => ({
        currentProfile: { email, userId },
        userType: 'CallCenterOperator',
      }))
  }

  return { currentProfile: null }
}

async function validatedProfile(
  context: Context,
  currentProfile: CurrentProfile
): Promise<CurrentProfile> {
  const {
    clients: { profile },
  } = context

  const { id, userId } = (await profile
    .getProfileInfo(currentProfile, context, 'id')
    .catch(() => {})) || { id: '', userId: '' } // 404 case.

  if (id) {
    return { userId, email: currentProfile.email }
  }

  return profile
    .createProfile(
      {
        email: currentProfile.email,
        userId,
      } as Profile,
      context
    )
    .then((newProfile: Profile) =>
      profile.getProfileInfo(
        { userId: newProfile.userId, email: '' },
        context,
        undefined
      )
    )
}

async function isValidCallcenterOperator(context: Context, email: string) {
  const {
    clients: { callCenterOperator, licenseManager },
    vtex: { authToken },
  } = context

  return licenseManager
    .getAccountData(authToken)
    .then(({ id }: any) =>
      callCenterOperator.isValidCallcenterOperator({ email, accountId: id })
    )
}

function isLogged(currentProfile: CurrentProfile | null) {
  return currentProfile?.email
}

async function checkUserAccount(
  context: Context,
  {
    currentProfile,
    userData: storeUser,
    userType,
  }: ProfileInfos<CurrentProfile>,
  resolverInfo: GraphQLResolveInfo
) {
  const {
    dataSources: { identity },
    vtex: { adminUserAuthToken, storeUserAuthToken, account },
  } = context

  if (!adminUserAuthToken && !storeUserAuthToken) {
    throw new AuthenticationError('')
  }

  let tokenUser = storeUser

  if (!tokenUser) {
    tokenUser = await identity.getUserWithToken(
      storeUserAuthToken! ?? adminUserAuthToken!
    )
  }

  if (tokenUser && 'account' in tokenUser && tokenUser.account !== account) {
    const {
      fieldName,
      returnType,
      operation: { operation, name },
    } = resolverInfo

    const {
      vtex: { logger, host },
      req: {
        headers: { 'user-agent': userAgent, referer },
      },
    } = context

    const logData = {
      host,
      referer,
      userAgent,
      message: 'Type: CrossTokenAccount',
      account,
      tokenAccount: tokenUser.account ?? '',
      caller: tokenUser.user ?? '',
      fieldName,
      fieldType: (returnType as any).name,
      operation: name?.value ? `${operation} ${name?.value}` : operation,
    }

    logger.warn(logData)
  }

  // If has admin user auth token, off course is a call center operator
  const isUserCallCenterOperator = userType === 'CallCenterOperator'

  if (
    tokenUser &&
    'id' in tokenUser &&
    !(
      tokenUser.account === account &&
      (isUserCallCenterOperator ||
        tokenUser.user.toLowerCase() === currentProfile?.email.toLowerCase() ||
        tokenUser.customerId === currentProfile?.userId)
    )
  ) {
    throw new AuthenticationError('Information conflict in tokenUser')
  }
}

```


[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 store-graphql/node/directives/toVtexAssets.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defaultFieldResolver, GraphQLField } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'

import { flags } from '../utils/featureFlags'

export class ToVtexAssets extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root, args, ctx: Context, info) => {
      const result = resolve(root, args, ctx, info)

      return flags.VTEX_ASSETS_URL && result
        ? result.replace('vteximg.com.br', 'vtexassets.com')
        : result
    }
  }
}

```


[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 store-graphql/node/directives/withOrderFormId.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defaultFieldResolver, GraphQLField } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'

import { getOrderFormIdFromCookie } from '../utils'

export class WithOrderFormId extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    const { resolve = defaultFieldResolver } = field

    field.resolve = async (root, args, ctx: Context, info) => {
      const checkoutOrderFormId = getOrderFormIdFromCookie(ctx.cookies)

      ctx.vtex.orderFormId = checkoutOrderFormId

      return resolve(root, args, ctx, info)
    }
  }
}

```


[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 store-graphql/node/directives/index.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { WithCurrentProfile } from './withCurrentProfile'
import { WithSegment } from './withSegment'
import { WithOrderFormId } from './withOrderFormId'
import { ToVtexAssets } from './toVtexAssets'
import { AuthorizationMetrics } from './authorizationMetrics'
import { WithOwnerId } from './withOwnerId'

export const schemaDirectives = {
  toVtexAssets: ToVtexAssets,
  withCurrentProfile: WithCurrentProfile,
  withSegment: WithSegment,
  withOrderFormId: WithOrderFormId,
  withOwnerId: WithOwnerId,
  withAuthMetrics: AuthorizationMetrics,
}

```


[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 store-graphql/node/dataSources/identity.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RequestOptions } from 'apollo-datasource-rest'
import { forEachObjIndexed } from 'ramda'

import { RESTDataSource } from './RESTDataSource'

export interface DefaultUser {
  authStatus: string
}

export interface User extends DefaultUser {
  id: string
  user: string
  customerId: string
  account: string
  audience: string
}

export class IdentityDataSource extends RESTDataSource {
  public getUserWithToken = (token: string) => {
    const {
      vtex: { account },
    } = this.context

    return this.post<DefaultUser | User>(
      `credential/validate?an=${account}`,
      {
        token,
      },
      { metric: 'vtexid-getUserWithToken' }
    )
  }

  public get baseURL() {
    return 'http://portal.vtexcommercestable.com.br/api/vtexid'
  }

  protected willSendRequest(request: RequestOptions) {
    const {
      vtex: { authToken },
    } = this.context

    forEachObjIndexed(
      (value: string, header) => request.headers.set(header, value),
      {
        'Proxy-Authorization': authToken,
        VtexIdClientAutCookie: authToken,
        'X-Vtex-Proxy-To': `http://portal.vtexcommercestable.com.br`,
      }
    )
  }
}

```


[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 store-graphql/node/dataSources/RESTDataSource.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ServiceContext } from '@vtex/api'
import { RESTDataSource as ApolloRESTDataSource } from 'apollo-datasource-rest'
import {
  BodyInit,
  RequestInit as ApolloRequestInit,
  URLSearchParamsInit,
} from 'apollo-server-env'

type Body = BodyInit | Record<string, unknown>

interface RequestInit extends ApolloRequestInit {
  metric?: string
}

export class RESTDataSource extends ApolloRESTDataSource<ServiceContext> {
  protected async get<TResult = any>(
    path: string,
    params?: URLSearchParamsInit,
    init?: RequestInit
  ): Promise<TResult> {
    return this.withMetrics(
      () => super.get<TResult>(path, params, init as any),
      init?.metric
    )
  }

  protected async post<TResult = any>(
    path: string,
    body?: Body,
    init?: RequestInit
  ): Promise<TResult> {
    return this.withMetrics(
      () => super.post<TResult>(path, body, init as any),
      init?.metric
    )
  }

  protected async patch<TResult = any>(
    path: string,
    body?: Body,
    init?: RequestInit
  ): Promise<TResult> {
    return this.withMetrics(
      () => super.patch<TResult>(path, body, init as any),
      init?.metric
    )
  }

  protected async put<TResult = any>(
    path: string,
    body?: Body,
    init?: RequestInit
  ): Promise<TResult> {
    return this.withMetrics(
      () => super.put<TResult>(path, body, init as any),
      init?.metric
    )
  }

  protected async delete<TResult = any>(
    path: string,
    params?: URLSearchParamsInit,
    init?: RequestInit
  ): Promise<TResult> {
    return this.withMetrics(
      () => super.delete<TResult>(path, params, init as any),
      init?.metric
    )
  }

  private withMetrics = async <TResult = any>(
    handler: () => Promise<TResult>,
    metric?: string
  ) => {
    const start = metric && process.hrtime()
    let status = 'APOLLO_NOT_ASSIGNED'

    try {
      status = 'APOLLO_REST_OK'

      return await handler()
    } catch (err) {
      status = 'APOLLO_REST_ERROR'
      throw err
    } finally {
      if (metric) {
        const label = `http-client-${status}-${metric}`

        metrics.batch(label, process.hrtime(start as [number, number]))
      }
    }
  }
}

```


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

[Assistant]
Here's the implementation:

```typescript
import { IdentityDataSource } from './identity'

export const dataSources = () => ({
  identity: new IdentityDataSource(),
})

```


[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 store-graphql/node/clients/callCenterOperator.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

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

import { statusToError } from '../utils'

export class CallCenterOperator extends ExternalClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super('http://licensemanager.vtex.com.br/api/pvt/accounts', ctx, {
      ...options,
      headers: {
        ...options?.headers,
        ...{ Accept: 'application/vnd.vtex.ds.v10+json' },
        ...(ctx.adminUserAuthToken
          ? { VtexIdclientAutCookie: ctx.adminUserAuthToken }
          : null),
      },
    })
  }

  public isValidCallcenterOperator = ({
    email,
    accountId,
  }: IsValidCallcenterOperatorArgs) =>
    this.get<boolean>(
      `${accountId}/products/2/logins/${email}/resources/Televendas/granted?ignoreIsAdmin=False`,
      { metric: 'callCenterOp-isValidCallcenterOperator' }
    )

  protected get = <T>(url: string, config?: RequestConfig) =>
    this.http.get<T>(url, config).catch(statusToError)
}

interface IsValidCallcenterOperatorArgs {
  email: string
  accountId: string
}

```


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

[User] Show me the implementation of store-graphql/node/clients/masterdata.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  ExternalClient,
  RequestConfig,
  UserInputError,
} from '@vtex/api'
import FormData from 'form-data'
import validator from 'validator'

import { statusToError } from '../utils'

const DATAENTITIES_PREFIX = '/dataentities'

export class MasterData extends ExternalClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(`http://api.vtex.com/${ctx.account}`, ctx, {
      ...options,
      headers: {
        ...options?.headers,
        ...{ Accept: 'application/vnd.vtex.ds.v10+json' },
        ...(ctx.adminUserAuthToken
          ? { VtexIdclientAutCookie: ctx.adminUserAuthToken }
          : null),
        ...(ctx.storeUserAuthToken
          ? { VtexIdclientAutCookie: ctx.storeUserAuthToken }
          : null),
      },
    })
  }

  public getSchema = <T>(dataEntity: string, schema: string) =>
    this.get<T>(this.routes.schema(dataEntity, schema), {
      metric: 'masterdata-getSchema',
    })

  public getPublicSchema = <T>(dataEntity: string, schema: string) =>
    this.get<T>(this.routes.publicSchema(dataEntity, schema), {
      metric: 'masterdata-getPublicSchema',
    })

  public getDocument = <T>(
    acronym: string,
    id: string,
    fields: string[],
    account?: string
  ) =>
    this.get<T>(this.routes.document(acronym, id), {
      metric: 'masterdata-getDocument',
      params: {
        _fields: generateFieldsArg(fields),
        ...(account ? { an: account } : null),
      },
    })

  public createDocument = (
    acronym: string,
    // eslint-disable-next-line @typescript-eslint/ban-types
    fields: object,
    schema?: string,
    account?: string
  ) =>
    this.post<DocumentResponse>(this.routes.documents(acronym), fields, {
      metric: 'masterdata-createDocument',
      params: {
        ...(schema ? { _schema: schema } : null),
        ...(account ? { an: account } : null),
      },
    })

  public updateDocument = (
    acronym: string,
    id: string,
    // eslint-disable-next-line @typescript-eslint/ban-types
    fields: object,
    account?: string,
    schema?: string
  ) =>
    this.patch(this.routes.document(acronym, id), fields, {
      metric: 'masterdata-updateDocument',
      params: {
        ...(schema ? { _schema: schema } : null),
        ...(account ? { an: account } : null),
      },
    })

  public searchDocuments = <T>(
    acronym: string,
    fields: string[],
    where: string,
    pagination: PaginationArgs,
    schema?: string,
    sort?: string,
    account?: string
  ) => {
    return this.get<T[]>(this.routes.search(acronym), {
      headers: paginationArgsToHeaders(pagination),
      metric: 'masterdata-searchDocuments',
      params: {
        _fields: generateFieldsArg(fields),
        _where: where,
        _sort: sort,
        ...(schema ? { _schema: schema } : null),
        ...(account ? { an: account } : null),
      },
    })
  }

  public deleteDocument = (acronym: string, id: string) =>
    this.delete(this.routes.document(acronym, id), {
      metric: 'masterdata-deleteDocument',
    })

  public uploadAttachment = (
    acronym: string,
    id: string,
    fields: string,
    formData: FormData
  ) =>
    this.post<any>(this.routes.attachments(acronym, id, fields), formData, {
      headers: formData.getHeaders(),
      metric: 'masterdata-uploadAttachment',
    })

  protected get = <T>(url: string, config?: RequestConfig) => {
    return this.http.get<T>(url, config).catch(statusToError)
  }

  protected post = <T>(url: string, data?: any, config?: RequestConfig) => {
    return this.http.post<T>(url, data, config).catch(statusToError)
  }

  protected delete = <T>(url: string, config?: RequestConfig) => {
    return this.http.delete<T>(url, config).catch(statusToError)
  }

  protected patch = <T>(url: string, data?: any, config?: RequestConfig) => {
    return this.http.patch<T>(url, data, config).catch(statusToError)
  }

  private get routes() {
    return {
      attachments: (acronym: string, id: string, fields: string) => {
        checkForURLsInStringArguments(acronym, id, fields)

        return `${DATAENTITIES_PREFIX}/${acronym}/documents/${id}/${fields}/attachments`
      },
      document: (acronym: string, id: string) => {
        checkForURLsInStringArguments(acronym, id)

        return `${DATAENTITIES_PREFIX}/${acronym}/documents/${id}`
      },
      documents: (acronym: string) => {
        checkForURLsInStringArguments(acronym)

        return `${DATAENTITIES_PREFIX}/${acronym}/documents`
      },
      schema: (acronym: string, schema: string) => {
        checkForURLsInStringArguments(acronym, schema)

        return `${DATAENTITIES_PREFIX}/${acronym}/schemas/${schema}`
      },
      publicSchema: (acronym: string, schema: string) => {
        checkForURLsInStringArguments(acronym, schema)

        return `${DATAENTITIES_PREFIX}/${acronym}/schemas/${schema}/public`
      },
      search: (acronym: string) => {
        checkForURLsInStringArguments(acronym)

        return `${DATAENTITIES_PREFIX}/${acronym}/search`
      },
    }
  }
}

function paginationArgsToHeaders({ page, pageSize }: PaginationArgs) {
  if (page < 1) {
    throw new UserInputError('Smallest page value is 1')
  }

  const startIndex = (page - 1) * pageSize
  const endIndex = startIndex + pageSize

  return {
    'REST-Range': `resources=${startIndex}-${endIndex}`,
  }
}

function generateFieldsArg(fields: string[]) {
  return fields.join(',')
}

/**
 * This function throws an error if any of the passed args are an URL.
 * We need to perform this check to protect our servers against possible
 * SSRF attacks.
 *
 * @param {...string[]} args
 */
function checkForURLsInStringArguments(...args: string[]) {
  for (let idx = 0; idx < args.length; idx++) {
    if (validator.isURL(args[idx])) {
      throw new UserInputError('Invalid arguments')
    }
  }
}

interface PaginationArgs {
  page: number
  pageSize: number
}

```


[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 store-graphql/node/clients/PvtCheckout.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  JanusClient,
  RequestConfig,
} from '@vtex/api'

import { statusToError } from '../utils'

export class PvtCheckout extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        ...(ctx.authToken ? { VtexIdclientAutCookie: ctx.authToken } : null),
        'x-vtex-user-agent': ctx.userAgent,
      },
    })
  }

  private getCommonHeaders = () => {
    const { segmentToken, sessionToken } = this.context as CustomIOContext

    const segmentTokenCookie = segmentToken
      ? `vtex_segment=${segmentToken};`
      : ''

    const sessionTokenCookie = sessionToken
      ? `vtex_session=${sessionToken};`
      : ''

    return {
      Cookie: `${segmentTokenCookie}${sessionTokenCookie}`,
    }
  }

  private getChannelQueryString = (salesChannel?: string) => {
    const { segment } = this.context as CustomIOContext
    const channel = salesChannel ?? segment?.channel

    return channel ? `?sc=${channel}` : ''
  }

  public simulation = (simulation: SimulationPayload, salesChannel?: string) =>
    this.post<SimulationOrderForm>(
      this.routes.simulation(this.getChannelQueryString(salesChannel)),
      simulation,
      {
        metric: 'pvt-checkout-simulation',
      }
    )

  protected post = <T>(url: string, data?: any, config: RequestConfig = {}) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http.post<T>(url, data, config).catch(statusToError) as Promise<
      T
    >
  }

  private get routes() {
    return {
      simulation: (queryString: string) =>
        `/api/checkout/pvt/orderForms/simulation${queryString}`,
    }
  }
}

```


[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 store-graphql/node/clients/checkout.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  JanusClient,
  RequestConfig,
  IOResponse,
  IOContext,
} from '@vtex/api'
import { AxiosError } from 'axios'

import { setCheckoutCookies } from '../resolvers/checkout'
import {
  checkoutCookieFormat,
  ownershipCookieFormat,
  OWNERSHIP_COOKIE,
  statusToError,
} from '../utils'

export class Checkout extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        ...(ctx.storeUserAuthToken
          ? { VtexIdclientAutCookie: ctx.storeUserAuthToken }
          : null),
        'x-vtex-user-agent': ctx.userAgent,
      },
    })
  }

  private getCommonHeaders = () => {
    const { orderFormId, ownerId, segmentToken, sessionToken } = this
      .context as CustomIOContext

    const checkoutCookie = orderFormId ? checkoutCookieFormat(orderFormId) : ''
    const ownershipCookie = ownerId ? ownershipCookieFormat(ownerId) : ''
    const segmentTokenCookie = segmentToken
      ? `vtex_segment=${segmentToken};`
      : ''

    const sessionTokenCookie = sessionToken
      ? `vtex_session=${sessionToken};`
      : ''

    return {
      Cookie: `${checkoutCookie}${ownershipCookie}${segmentTokenCookie}${sessionTokenCookie}`,
    }
  }

  private getChannelQueryString = () => {
    const { segment } = this.context as CustomIOContext
    const channel = segment?.channel
    const queryString = channel ? `?sc=${channel}` : ''

    return queryString
  }

  public addItem = (orderFormId: string, items: any) =>
    this.post<OrderForm>(
      this.routes.addItem(orderFormId, this.getChannelQueryString()),
      { orderItems: items },
      { metric: 'checkout-addItem' }
    )

  public cancelOrder = (orderFormId: string, reason: string) =>
    this.post(
      this.routes.cancelOrder(orderFormId),
      { reason },
      { metric: 'checkout-cancelOrder' }
    )

  public setOrderFormCustomData = (
    orderFormId: string,
    appId: string,
    field: string,
    value: any
  ) =>
    this.put(
      this.routes.orderFormCustomData(orderFormId, appId, field),
      { value },
      { metric: 'checkout-setOrderFormCustomData' }
    )

  public updateItems = (orderFormId: string, orderItems: any) =>
    this.post(
      this.routes.updateItems(orderFormId),
      { orderItems },
      { metric: 'checkout-updateItems' }
    )

  public updateOrderFormIgnoreProfile = (
    orderFormId: string,
    ignoreProfileData: boolean
  ) =>
    this.patch(
      this.routes.profile(orderFormId),
      { ignoreProfileData },
      { metric: 'checkout-updateOrderFormIgnoreProfile' }
    )

  public updateOrderFormPayment = (orderFormId: string, payments: any) =>
    this.post(
      this.routes.attachmentsData(orderFormId, 'paymentData'),
      { payments },
      { metric: 'checkout-updateOrderFormPayment' }
    )

  public updateOrderFormProfile = async (
    orderFormId: string,
    fields: any,
    ctx: Context
  ) => {
    const { data, headers } = await this.postRaw(
      this.routes.attachmentsData(orderFormId, 'clientProfileData'),
      fields,
      { metric: 'checkout-updateOrderFormProfile' }
    )

    setCheckoutCookies(headers, ctx, [OWNERSHIP_COOKIE])

    return data
  }

  public updateOrderFormShipping = (orderFormId: string, shipping: any) =>
    this.post(
      this.routes.attachmentsData(orderFormId, 'shippingData'),
      shipping,
      { metric: 'checkout-updateOrderFormShipping' }
    )

  public updateOrderFormMarketingData = (
    orderFormId: string,
    marketingData: any
  ) =>
    this.post(
      this.routes.attachmentsData(orderFormId, 'marketingData'),
      marketingData,
      { metric: 'checkout-updateOrderFormMarketingData' }
    )

  public updateOrderFormClientPreferencesData = (
    orderFormId: string,
    clientPreferencesData: OrderFormClientPreferencesData
  ) => {
    // The API default value of `optinNewsLetter` is `null`, but it doesn't accept a POST with its value as `null`
    const filteredClientPreferencesData =
      clientPreferencesData.optinNewsLetter === null
        ? { locale: clientPreferencesData.locale }
        : clientPreferencesData

    return this.post(
      this.routes.attachmentsData(orderFormId, 'clientPreferencesData'),
      filteredClientPreferencesData,
      { metric: 'checkout-updateOrderFormClientPreferencesData' }
    )
  }

  public addAssemblyOptions = async (
    orderFormId: string,
    itemId: string | number,
    assemblyOptionsId: string,
    body: any
  ) =>
    this.post<OrderForm>(
      this.routes.assemblyOptions(orderFormId, itemId, assemblyOptionsId),
      body,
      { metric: 'checkout-addAssemblyOptions' }
    )

  public removeAssemblyOptions = async (
    orderFormId: string,
    itemId: string | number,
    assemblyOptionsId: string,
    body: any
  ) =>
    this.delete<OrderForm>(
      this.routes.assemblyOptions(orderFormId, itemId, assemblyOptionsId),
      { metric: 'checkout-removeAssemblyOptions', data: body }
    )

  public updateOrderFormCheckin = (orderFormId: string, checkinPayload: any) =>
    this.post(this.routes.checkin(orderFormId), checkinPayload, {
      metric: 'checkout-updateOrderFormCheckin',
    })

  public orderForm = (orderFormId?: string) => {
    return this.post<OrderForm>(
      this.routes.orderForm(orderFormId),
      { expectedOrderFormSections: ['items'] },
      { metric: 'checkout-orderForm' }
    )
  }

  public orderFormRaw = () => {
    return this.postRaw<OrderForm>(
      this.routes.orderForm(),
      { expectedOrderFormSections: ['items'] },
      { metric: 'checkout-orderForm' }
    )
  }

  public newOrderForm = (orderFormId?: string) => {
    return this.http
      .postRaw<OrderForm>(this.routes.orderForm(orderFormId), undefined, {
        metric: 'checkout-newOrderForm',
      })
      .catch(statusToError) as Promise<IOResponse<OrderForm>>
  }

  public changeToAnonymousUser = (orderFormId: string) => {
    return this.get(this.routes.changeToAnonymousUser(orderFormId), {
      metric: 'checkout-change-to-anonymous',
    }).catch((err) => {
      // This endpoint is expected to return a redirect to
      // the user, so we can ignore the error if it is a 3xx
      if (!err.response || /^3..$/.test((err as AxiosError).code ?? '')) {
        throw err
      }
    })
  }

  // Deprecated: This endpoint is deprecated and any request will return an empty array
  public orders = () =>
    this.get(this.routes.orders, { metric: 'checkout-orders' }).catch((err) => {
      if (err.response && err.response.status === 405) {
        return []
      }

      throw err
    })

  public simulation = (simulation: SimulationPayload) =>
    this.post<SimulationOrderForm>(
      this.routes.simulation(this.getChannelQueryString()),
      simulation,
      {
        metric: 'checkout-simulation',
      }
    )

  protected get = <T>(url: string, config: RequestConfig = {}) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http.get<T>(url, config).catch(statusToError) as Promise<T>
  }

  protected post = <T>(url: string, data?: any, config: RequestConfig = {}) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http.post<T>(url, data, config).catch(statusToError) as Promise<
      T
    >
  }

  protected postRaw = async <T>(
    url: string,
    data?: any,
    config: RequestConfig = {}
  ) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http
      .postRaw<T>(url, data, config)
      .catch(statusToError) as Promise<IOResponse<T>>
  }

  protected delete = <T>(url: string, config: RequestConfig = {}) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http.delete<T>(url, config).catch(statusToError) as Promise<
      IOResponse<T>
    >
  }

  protected patch = <T>(
    url: string,
    data?: any,
    config: RequestConfig = {}
  ) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http
      .patch<T>(url, data, config)
      .catch(statusToError) as Promise<T>
  }

  protected put = <T>(url: string, data?: any, config: RequestConfig = {}) => {
    config.headers = {
      ...config.headers,
      ...this.getCommonHeaders(),
    }

    return this.http.put<T>(url, data, config).catch(statusToError) as Promise<
      T
    >
  }

  private get routes() {
    const base = '/api/checkout/pub'

    return {
      addItem: (orderFormId: string, queryString: string) =>
        `${base}/orderForm/${orderFormId}/items${queryString}`,
      cancelOrder: (orderFormId: string) =>
        `${base}/orders/${orderFormId}/user-cancel-request`,
      orderFormCustomData: (
        orderFormId: string,
        appId: string,
        field: string
      ) => `${base}/orderForm/${orderFormId}/customData/${appId}/${field}`,
      updateItems: (orderFormId: string) =>
        `${base}/orderForm/${orderFormId}/items/update`,
      profile: (orderFormId: string) =>
        `${base}/orderForm/${orderFormId}/profile`,
      attachmentsData: (orderFormId: string, field: string) =>
        `${base}/orderForm/${orderFormId}/attachments/${field}`,
      assemblyOptions: (
        orderFormId: string,
        itemId: string | number,
        assemblyOptionsId: string
      ) =>
        `${base}/orderForm/${orderFormId}/items/${itemId}/assemblyOptions/${assemblyOptionsId}`,
      checkin: (orderFormId: string) =>
        `${base}/orderForm/${orderFormId}/checkIn`,
      orderForm: (orderFormId?: string) =>
        `${base}/orderForm/${orderFormId ?? ''}`,
      orders: `${base}/orders`,
      simulation: (queryString: string) =>
        `${base}/orderForms/simulation${queryString}`,
      changeToAnonymousUser: (orderFormId: string) =>
        `/checkout/changeToAnonymousUser/${orderFormId}`,
    }
  }
}

```


[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 store-graphql/node/clients/licenseManagerExtended.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  LicenseManager,
  RequestConfig,
} from '@vtex/api'

import { statusToError } from '../utils'

const FIVE_SECONDS_MS = 5 * 1000

export class LicenseManagerExtendedClient extends LicenseManager {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(context, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdClientAutCookie: context.authToken ?? '',
      },
      timeout: FIVE_SECONDS_MS,
    })
  }

  public getCurrentAccount = (customFields?: string) =>
    this.get<Account>(`${this.baseUrl}/${this.context.account}`, {
      metric: 'account-getAccount',
      params: {
        extraFields: customFields,
      },
    }).then((account: Account) => {
      account.PIIEnabled = Boolean(account.Privacy)

      return account
    })

  protected get = <T>(url: string, config?: RequestConfig) =>
    this.http.get<T>(url, config).catch<any>(statusToError)

  private baseUrl = '/api/pvt/accounts'
}

```


[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 store-graphql/node/clients/session.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { JanusClient } from '@vtex/api'
import parseCookie from 'cookie'

interface VtexIdCookies {
  account: string | null
  id: string | null
}

const SESSION_COOKIE = 'vtex_session'

const routes = {
  base: '/api/sessions',
}

export class Session extends JanusClient {
  /**
   * Get the session data using the given token
   */
  public getSession = async (token: string, items: string[]) => {
    const { data: sessionData, headers } = await this.http.getRaw(routes.base, {
      headers: {
        'Content-Type': 'application/json',
        Cookie: `vtex_session=${token};`,
      },
      metric: 'session-get',
      params: {
        items: items.join(','),
      },
    })

    return {
      sessionData,
      sessionToken: extractSessionCookie(headers) ?? token,
    }
  }

  /**
   * Update the public portion of this session
   */
  public updateSession = (
    key: string,
    value: any,
    items: string[],
    token: any,
    vtexIdCookies: VtexIdCookies
  ) => {
    const data = { public: { [key]: { value } } }
    let cookies = `vtex_session=${token};`

    if (vtexIdCookies.account) {
      cookies += `${vtexIdCookies.account};`
    }

    if (vtexIdCookies.id) {
      cookies += `${vtexIdCookies.id};`
    }

    const config = {
      headers: {
        'Content-Type': 'application/json',
        Cookie: cookies,
      },
      metric: 'session-update',
      params: {
        items: items.join(','),
      },
    }

    return this.http.post(routes.base, data, config)
  }
}

function extractSessionCookie(headers: Record<string, string>) {
  for (const setCookie of headers['set-cookie'] ?? []) {
    const parsedCookie = parseCookie.parse(setCookie)
    const sessionCookie = parsedCookie[SESSION_COOKIE]

    if (sessionCookie != null) {
      return sessionCookie
    }
  }

  return null
}

```


[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 store-graphql/node/clients/oms.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  JanusClient,
  RequestConfig,
} from '@vtex/api'

import { statusToError } from '../utils'

export class OMS extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        ...(ctx.storeUserAuthToken
          ? { VtexIdclientAutCookie: ctx.storeUserAuthToken }
          : null),
      },
    })
  }

  public userLastOrder = () =>
    this.get(this.routes.lastOrder, { metric: 'oms-userLastOrder' })

  public order = (id: string) =>
    this.get(this.routes.order(id), { metric: 'oms-order' })

  protected get = <T>(url: string, config: RequestConfig = {}) => {
    const { segmentToken, sessionToken } = this.context as CustomIOContext
    const segmentTokenCookie = segmentToken
      ? `vtex_segment=${segmentToken};`
      : ''

    const sessionTokenCookie = sessionToken
      ? `vtex_session=${sessionToken};`
      : ''

    config.headers = {
      ...config.headers,
      Cookie: `${segmentTokenCookie}${sessionTokenCookie}`,
    }

    return this.http.get<T>(url, config).catch(statusToError)
  }

  private get routes() {
    const base = '/api/oms'

    return {
      lastOrder: `${base}/user/orders/last`,
      order: (id: string) => `${base}/pvt/orders/${id}`,
    }
  }

  public getEmailRetificationConfig() {
    return this.http.get('/api/oms/configuration/email-rectification-enabled', {
      headers: { VtexIdclientAutCookie: this.context.authToken },
    })
  }
}

```


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

[User] Show me the implementation of store-graphql/node/clients/logistics.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  JanusClient,
  RequestConfig,
} from '@vtex/api'

import { statusToError } from '../utils'
import {
  LogisticOutput,
  LogisticPickupPoint,
} from '../resolvers/logistics/types'

const FOUR_SECONDS = 4 * 1000

export class LogisticsClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.authToken,
      },
      timeout: FOUR_SECONDS,
    })
  }

  public pickupById = (id: string) =>
    this.get<LogisticPickupPoint>(this.routes.pickUpById(id), {
      metric: 'logistics-pickupById',
    })

  public nearPickupPoints = (lat: string, long: string, maxDistance = 50) =>
    this.get<LogisticOutput>(
      this.routes.nearPickupPoints(lat, long, maxDistance),
      {
        metric: 'logistics-nearPickupPoints',
      }
    )

  public shipping = () =>
    this.get(this.routes.shipping, {
      metric: 'logistics-shipping',
    })

  protected get = <T>(url: string, config?: RequestConfig) =>
    this.http.get<T>(url, config).catch(statusToError) as Promise<T>

  private get routes() {
    const basePVT = '/api/logistics'

    return {
      shipping: `${basePVT}/pub/shipping/configuration`,
      nearPickupPoints: (lat: string, long: string, maxDistance: number) =>
        `${basePVT}/pvt/configuration/pickuppoints/_search?&page=1&pageSize=100&lat=${lat}&lon=${long}&maxDistance=${maxDistance}`,
      pickUpById: (id: string) =>
        `${basePVT}/pvt/configuration/pickuppoints/${id}`,
    }
  }
}

```


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

[User] Show me the implementation of store-graphql/node/clients/rewriter.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  AppGraphQLClient,
  IOContext,
  InstanceOptions,
  GraphQLResponse,
  Serializable,
} from '@vtex/api'

const getRouteQuery = `query GetRoute($id: String!, $type: String!) {
  internal {
    routes(locator: {id:$id, type:$type}) {
      route
      binding
    }
  }
}
`

interface Route {
  route: string
  binding: string
}

interface GetRoutesResponse {
  internal: {
    routes: Route[]
  }
}

class CustomGraphQLError extends Error {
  public graphQLErrors: any

  constructor(message: string, graphQLErrors: any[]) {
    super(message)
    this.graphQLErrors = graphQLErrors
  }
}

export function throwOnGraphQLErrors<T extends Serializable>(message: string) {
  return function maybeGraphQLResponse(response: GraphQLResponse<T>) {
    // eslint-disable-next-line no-self-compare
    if (response?.errors?.length || 0 > 0) {
      throw new CustomGraphQLError(message, response.errors!)
    }

    return response
  }
}

export class Rewriter extends AppGraphQLClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super('vtex.rewriter@1.x', context, {
      ...options,
      headers: {
        ...options?.headers,
      },
    })
  }

  public getRoute = async (id: string, type: string, bindingId: string) => {
    const responseData = await this.graphql
      .query<GetRoutesResponse, { id: string; type: string }>(
        {
          query: getRouteQuery,
          variables: { id, type },
        },
        {
          metric: 'search-get-route',
        }
      )
      .then(throwOnGraphQLErrors('Error getting route data from vtex.rewriter'))
      .then((data) => {
        return data.data!.internal.routes
      })

    return responseData.find((route) => route.binding === bindingId)?.route
  }
}

```


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

[Assistant]
Here's the implementation:

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

import { CallCenterOperator } from './callCenterOperator'
import { Catalog } from './catalog'
import { Checkout } from './checkout'
import { PvtCheckout } from './PvtCheckout'
import { MasterData } from './masterdata'
import { ProfileClient } from './profile'
import { ProfileClientV1 } from './profile/profileV1'
import { ProfileClientV2 } from './profile/profileV2'
import { LicenseManagerExtendedClient } from './licenseManagerExtended'
import { OMS } from './oms'
import { Portal } from './portal'
import { LogisticsClient } from './logistics'
import { Session } from './session'
import { Rewriter } from './rewriter'

export class Clients extends IOClients {
  public get masterdata() {
    return this.getOrSet('masterdata', MasterData)
  }

  public get checkout() {
    return this.getOrSet('checkout', Checkout)
  }

  public get pvtCheckout() {
    return this.getOrSet('pvtCheckout', PvtCheckout)
  }

  public get callCenterOperator() {
    return this.getOrSet('callCenterOperator', CallCenterOperator)
  }

  public get catalog() {
    return this.getOrSet('catalog', Catalog)
  }

  public get profile() {
    return this.getOrSet('profile', ProfileClient)
  }

  public get profileV1() {
    return this.getOrSet('profileV1', ProfileClientV1)
  }

  public get profileV2() {
    return this.getOrSet('profileV2', ProfileClientV2)
  }

  public get licenseManagerExtended() {
    return this.getOrSet('licenseManagerExtended', LicenseManagerExtendedClient)
  }

  public get oms() {
    return this.getOrSet('oms', OMS)
  }

  public get portal() {
    return this.getOrSet('portal', Portal)
  }

  public get logistics() {
    return this.getOrSet('logistics', LogisticsClient)
  }

  public get customSession() {
    return this.getOrSet('customSession', Session)
  }

  public get rewriter() {
    return this.getOrSet('rewriter', Rewriter)
  }
}

```


[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 store-graphql/node/clients/portal.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InstanceOptions,
  IOContext,
  JanusClient,
  RequestConfig,
} from '@vtex/api'

import { statusToError } from '../utils'

export class Portal extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.authToken,
      },
    })
  }

  public sites = () =>
    this.get<Site[]>(this.routes.allSites(), { metric: 'portal-sites' })

  public storeConfigs = (activeSite: string) =>
    this.get(this.routes.storeConfigs(activeSite), {
      metric: 'portal-site-config',
    })

  public defaultSalesChannel = () =>
    this.get<SalesChannel>(this.routes.scDefault, {
      metric: 'portal-default-sales-channel',
    })

  protected get = <T>(url: string, config?: RequestConfig) =>
    this.http.get<T>(url, config).catch(statusToError)

  private get routes() {
    const basePVT = '/api/portal/pvt'

    return {
      allSites: () => `${basePVT}/sites/`,
      storeConfigs: (activeSite: string) =>
        `${basePVT}/sites/${activeSite}/configuration`,
      scDefault: '/api/catalog_system/pub/saleschannel/default',
    }
  }
}

export interface Site {
  id: string
  title: string
  siteName: string
}

export interface SalesChannel {
  Id: string
  Name: string
  IsActive: true
  ProductClusterId: string | null
  CountryCode: string
  CultureInfo: string
  TimeZone: string
  CurrencyCode: string
  CurrencySymbol: string
  CurrencyLocale: number
  CurrencyFormatInfo: {
    CurrencyDecimalDigits: number
    CurrencyDecimalSeparator: string
    CurrencyGroupSeparator: string
    CurrencyGroupSize: number
    StartsWithCurrencySymbol: boolean
  }
  Origin: any
  Position: number
  ConditionRule: 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 store-graphql/node/clients/catalog.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  AppClient,
  InstanceOptions,
  IOContext,
  RequestConfig,
  SegmentData,
} from '@vtex/api'
import { stringify } from 'qs'

import { CatalogCrossSellingTypes } from '../resolvers/catalog/utils'

interface AutocompleteArgs {
  maxRows: string
  searchTerm: string
}

const inflightKey = ({ baseURL, url, params, headers }: RequestConfig) => {
  const segmentToken = headers && headers['x-vtex-segment']
  const segmentQs = segmentToken ? `&segmentToken=${segmentToken}` : ''

  return (
    baseURL! +
    url! +
    stringify(params, { arrayFormat: 'repeat', addQueryPrefix: true }) +
    segmentQs
  )
}

interface CategoryWithNulls
  extends Pick<
    Category,
    'id' | 'name' | 'hasChildren' | 'MetaTagDescription' | 'Title'
  > {
  url: null
  children: null
}

interface CatalogPageTypeResponse {
  id: string
  pageType: string
  name: string
  url: string
  title: string | null
  metaTagDescription: string | null
}

/** Catalog API
 * Docs: https://documenter.getpostman.com/view/845/catalogsystem-102/Hs44
 */
export class Catalog extends AppClient {
  private basePath: string
  constructor(ctx: IOContext, opts?: InstanceOptions) {
    super('vtex.catalog-api-proxy@0.x', ctx, opts)
    this.basePath = ctx.sessionToken
      ? '/proxy/authenticated/catalog'
      : '/proxy/catalog'
  }

  private removeSpecialCharacters = (str: string) => {
    return str.replace(/[%"'.()+]/g, '')
  }

  public pageType = (path: string, query = '') => {
    const pageTypePath = path.startsWith('/') ? path.substr(1) : path

    const pageTypeQuery = !query || query.startsWith('?') ? query : `?${query}`

    return this.get<CatalogPageTypeResponse>(
      `/pub/portal/pagetype/${pageTypePath}${pageTypeQuery}`,
      { metric: 'catalog-pagetype' }
    )
  }

  public salesChannelAvailable = (email?: string) =>
    this.get<SalesChannelAvailable[]>(
      `/pub/saleschannel/available${
        // If we dont pass the email query string, it will return all open Trade Policies
        email ? `?email=${encodeURIComponent(email)}` : ''
      }`,
      {
        metric: 'catalog-sales-channel-available',
      }
    )

  public product = (slug: string) =>
    this.get<Product[]>(`/pub/products/search/${slug?.toLowerCase()}/p`, {
      metric: 'catalog-product',
    })

  public productByEan = (id: string) =>
    this.get<Product[]>(`/pub/products/search?fq=alternateIds_Ean:${id}`, {
      metric: 'catalog-productByEan',
    })

  public productsByEan = (ids: string[]) =>
    this.get<Product[]>(
      `/pub/products/search?${ids
        .map((id) => `fq=alternateIds_Ean:${id}`)
        .join('&')}`,
      { metric: 'catalog-productByEan' }
    )

  public productById = (id: string) =>
    this.get<Product[]>(`/pub/products/search?fq=productId:${id}`, {
      metric: 'catalog-productById',
    })

  public productsById = (ids: string[]) =>
    this.get<Product[]>(
      `/pub/products/search?${ids.map((id) => `fq=productId:${id}`).join('&')}`,
      { metric: 'catalog-productById' }
    )

  public productByReference = (id: string) =>
    this.get<Product[]>(`/pub/products/search?fq=alternateIds_RefId:${id}`, {
      metric: 'catalog-productByReference',
    })

  public productsByReference = (ids: string[]) =>
    this.get<Product[]>(
      `/pub/products/search?${ids
        .map((id) => `fq=alternateIds_RefId:${id}`)
        .join('&')}`,
      { metric: 'catalog-productByReference' }
    )

  public productBySku = (skuIds: string[]) =>
    this.get<Product[]>(
      `/pub/products/search?${skuIds
        .map((skuId) => `fq=skuId:${skuId}`)
        .join('&')}`,
      { metric: 'catalog-productBySku' }
    )

  public products = (args: SearchArgs, useRaw = false) => {
    const method = useRaw ? this.getRaw : this.get

    return method<Product[]>(this.productSearchUrl(args), {
      metric: 'catalog-products',
    })
  }

  public productsQuantity = async (args: SearchArgs) => {
    const {
      headers: { resources },
    } = await this.getRaw(this.productSearchUrl(args))

    const [, quantity] = resources.split('/')

    return parseInt(quantity, 10)
  }

  public brands = () =>
    this.get<Brand[]>('/pub/brand/list', { metric: 'catalog-brands' })

  public brand = (id: number) =>
    this.get<Brand[]>(`/pub/brand/${id}`, { metric: 'catalog-brands' })

  public categories = (treeLevel: number) =>
    this.get<Category[]>(`/pub/category/tree/${treeLevel}/`, {
      metric: 'catalog-categories',
    })

  public facets = (facets = '') => {
    const [path, options] = decodeURI(facets).split('?')

    return this.get(
      `/pub/facets/search/${encodeURI(
        `${this.removeSpecialCharacters(path.trim())}${
          options ? `?${options}` : ''
        }`
      )}`,
      { metric: 'catalog-facets' }
    )
  }

  public category = (id: string | number) =>
    this.get<CategoryWithNulls>(`/pub/category/${id}`, {
      metric: 'catalog-category',
    })

  public crossSelling = (id: string, type: CatalogCrossSellingTypes) =>
    this.get<Product[]>(`/pub/products/crossselling/${type}/${id}`, {
      metric: 'catalog-crossSelling',
    })

  public autocomplete = ({ maxRows, searchTerm }: AutocompleteArgs) =>
    this.get<{ itemsReturned: Item[] }>(
      `/buscaautocomplete?maxRows=${maxRows}&productNameContains=${encodeURIComponent(
        searchTerm
      )}`,
      { metric: 'catalog-autocomplete' }
    )

  private get = <T = any>(url: string, config: RequestConfig = {}) => {
    const segmentData: SegmentData | undefined = (this
      .context! as CustomIOContext).segment

    const { channel: salesChannel = '' } = segmentData ?? {}

    config.params = {
      ...config.params,
      ...(!!salesChannel && { sc: salesChannel }),
    }

    config.inflightKey = inflightKey

    return this.http.get<T>(`${this.basePath}${url}`, config)
  }

  private getRaw = <T = any>(url: string, config: RequestConfig = {}) => {
    const segmentData: SegmentData | undefined = (this
      .context! as CustomIOContext).segment

    const { channel: salesChannel = '' } = segmentData ?? {}

    config.params = {
      ...config.params,
      ...(!!salesChannel && { sc: salesChannel }),
    }

    config.inflightKey = inflightKey

    return this.http.getRaw<T>(`${this.basePath}${url}`, config)
  }

  private productSearchUrl = ({
    query = '',
    category = '',
    specificationFilters,
    priceRange = '',
    collection = '',
    salesChannel = '',
    orderBy = '',
    from = 0,
    to = 9,
    map = '',
    hideUnavailableItems = false,
  }: SearchArgs) => {
    const sanitizedQuery = encodeURIComponent(
      this.removeSpecialCharacters(decodeURIComponent(query ?? '').trim())
    )

    if (hideUnavailableItems) {
      const segmentData = (this.context as CustomIOContext).segment

      salesChannel = segmentData?.channel.toString() ?? ''
    }

    let url = `/pub/products/search/${sanitizedQuery}?`

    if (category && !query) {
      url += `&fq=C:/${category}/`
    }

    if (specificationFilters && specificationFilters.length > 0) {
      url = `${url}${specificationFilters.map((filter) => `&fq=${filter}`)}`
    }

    if (priceRange) {
      url += `&fq=P:[${priceRange}]`
    }

    if (collection) {
      url += `&fq=productClusterIds:${collection}`
    }

    if (salesChannel) {
      url += `&fq=isAvailablePerSalesChannel_${salesChannel}:1`
    }

    if (orderBy) {
      url += `&O=${orderBy}`
    }

    if (map) {
      url += `&map=${map}`
    }

    if (from != null && from > -1) {
      url += `&_from=${from}`
    }

    if (to != null && to > -1) {
      url += `&_to=${to}`
    }

    return url
  }
}

```


[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 store-graphql/node/typings/Checkout.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface OrderFormMarketingData {
  utmCampaign?: string
  utmMedium?: string
  utmSource?: string
  utmiCampaign?: string
  utmiPart?: string
  utmipage?: string
  marketingTags?: string | string[]
}

interface CheckoutAddress {
  addressType: string
  receiverName: string | null
  addressId: string
  postalCode: string
  city: string
  state: string
  country: string
  street: string
  number: string
  neighborhood: string
  complement: string
  reference: string | null
  geoCoordinates: [number, number]
}

interface CheckoutAssemblyItem {
  id: string
  inputValues: Record<string, string>
}

interface CheckoutAttachmentOffering {
  name: string
  required: boolean
  schema: Record<string, Record<string, unknown>>
}

interface OrderFormItem {
  id: string
  name: string
  detailUrl: string
  imageUrl: string
  productRefId: string
  skuName: string
  quantity: number
  uniqueId: string
  productId: string
  refId: string
  ean: string
  priceValidUntil: string
  price: number
  tax: number
  listPrice: number
  sellingPrice: number
  rewardValue: number
  isGift: boolean
  parentItemIndex: number | null
  parentAssemblyBinding: string | null
  productCategoryIds: string
  priceTags: PriceTags[]
  measurementUnit: string
  additionalInfo: {
    brandName: string
    brandId: string
    offeringInfo: any | null
    offeringType: any | null
    offeringTypeId: any | null
  }
  productCategories: Record<string, string>
  seller: string
  sellerChain: string[]
  availability: string
  unitMultiplier: number
  assemblies: CheckoutAssemblyItem[]
  attachmentOfferings: CheckoutAttachmentOffering[]
  priceDefinition: {
    calculatedSellingPrice: number
    sellingPrices: SellingPrice[]
    total: number
  }
}

interface SellingPrice {
  quantity: number
  value: number
}

interface PriceTags {
  name: string
  value: number
  rawValue: number
  isPercentual: boolean
  identifier: string
}

interface InstallmentOption {
  paymentSystem: string
  paymentName: string
  paymentGroupName: string
  value: number
  bin: string | null
  installments: SimulationInstallment[]
}

interface SimulationInstallment {
  value: number
  interestRate: number
  total: number
  count: number
}

interface PaymentSystem {
  id: number
  name: string
  groupName: string
  validator: Validator
  stringId: string
  template: string
  requiresDocument: boolean
  displayDocument: boolean
  isCustom: boolean
  description: string | null
  requiresAuthentication: boolean
  dueDate: string
  availablePayments: any
}

interface Validator {
  regex: string
  mask: string
  cardCodeRegex: string
  cardCodeMask: string
  weights: number[]
  useCvv: boolean
  useExpirationDate: boolean
  useCardHolderName: boolean
  useBillingAddress: boolean
}

interface OrderForm {
  orderFormId: string
  salesChannel: string
  loggedIn: boolean
  isCheckedIn: boolean
  storeId: string | null
  checkedInPickupPointId: string | null
  allowManualPrice: boolean
  canEditData: boolean
  userProfileId: string | null
  userType: string | null
  ignoreProfileData: boolean
  value: number
  messages: any[]
  items: OrderFormItem[]
  selectableGifts: any[]
  totalizers: Array<{ id: string; name: string; value: number }>
  shippingData: {
    address: CheckoutAddress
    logisticsInfo: LogisticsInfo[]
    selectedAddresses: CheckoutAddress[]
    availableAddresses: CheckoutAddress[]
    pickupPoints: Array<{
      friendlyName: string
      address: CheckoutAddress
      additionalInfo: string
      id: string
      businessHours: Array<{
        DayOfWeek: number
        OpeningTime: string
        ClosingTime: string
      }>
    }>
  }
  clientProfileData: any | null
  paymentData: PaymentData
  marketingData: OrderFormMarketingData | null
  sellers: Array<{
    id: string
    name: string
    logo: string
  }>
  clientPreferencesData: OrderFormClientPreferencesData
  commercialConditionData: any | null
  storePreferencesData: {
    countryCode: string
    saveUserData: boolean
    timeZone: string
    currencyCode: string
    currencyLocale: number
    currencySymbol: string
    currencyFormatInfo: {
      currencyDecimalDigits: number
      currencyDecimalSeparator: string
      currencyGroupSeparator: string
      currencyGroupSize: number
      startsWithCurrencySymbol: boolean
    }
  }
  giftRegistryData: any | null
  openTextField: any | null
  invoiceData: any | null
  customData: any | null
  itemMetadata: {
    items: MetadataItem[]
  }
  hooksData: any | null
  ratesAndBenefitsData: {
    rateAndBenefitsIdentifiers: any[]
    teaser: any[]
  }
  subscriptionData: any | null
  itemsOrdination: any | null
}

interface OrderFormClientPreferencesData {
  locale: string
  optinNewsLetter: boolean | null
}

interface OrderFormItemInput {
  id?: number
  index?: number
  quantity?: number
  seller?: string
  inputValues: Record<string, string>
  options?: AssemblyOptionInput[]
}

interface AssemblyOptionInput {
  id: string
  quantity: number
  assemblyId: string
  seller: string
  inputValues: Record<string, string>
  options?: AssemblyOptionInput[]
}

interface PayloadItem {
  id: string
  quantity: number
  seller: string
  parentItemIndex?: number | null
  parentAssemblyBinding?: string | null
  country?: string
  postalCode?: string
}

interface SimulationPayload {
  country?: string
  items: PayloadItem[]
  postalCode?: string
  isCheckedIn?: boolean
  priceTables?: string[]
  marketingData?: Record<string, string>
  geoCoordinates?: [string | number, string | number]
  shippingData?: any
}

interface SLAItem {
  id: string
  deliveryChannel: string
  name: string
  deliveryIds: Array<{
    courierId: string
    warehouseId: string
    dockId: string
    courierName: string
    quantity: number
  }>
  shippingEstimate: string
  shippingEstimateDate: string | null
  lockTTL: string | null
  availableDeliveryWindows: any[]
  deliveryWindow: string | null
  price: number
  listPrice: number
  tax: number
  pickupStoreInfo: {
    isPickupStore: boolean
    friendlyName: string | null
    address: CheckoutAddress | null
    additionalInfo: any | null
    dockId: string | null
  }
  pickupPointId: string | null
  pickupDistance: number
  polygonName: string | null
}

interface LogisticsInfo {
  itemIndex: number
  selectedSla: string | null
  selectedDeliveryChannel: string | null
  addressId: string
  slas: SLAItem[]
  shipsTo: string[]
  itemId: string
  deliveryChannels: Array<{ id: string }>
}

interface SimulationOrderForm extends OrderForm {
  logisticsInfo?: LogisticsInfo[]
}

interface SLA {
  id: string
  deliveryChannel: string
  name: string
  deliveryIds: Array<{
    courierId: string
    warehouseId: string
    dockId: string
    courierName: string
    quantity: number
  }>
  shippingEstimate: string
  shippingEstimateDate: string | null
  lockTTL: string | null
  availableDeliveryWindows: any[]
  deliveryWindow: string | null
  price: number
  listPrice: number
  tax: number
  pickupStoreInfo: {
    isPickupStore: boolean
    friendlyName: string | null
    address: CheckoutAddress | null
    additionalInfo: any | null
    dockId: string | null
  }
  pickupPointId: string | null
  pickupDistance: number
  polygonName: string | null
}

interface ItemWithSimulationInput {
  itemId: string
  sellers: Array<{
    sellerId: string
  }>
}

interface Installment {
  count: number
  hasInterestRate: boolean
  interestRate: number
  value: number
  total: number
  sellerMerchantInstallments: Array<{
    id: string
    count: number
    hasInterestRate: boolean
    interestRate: number
    value: number
    total: number
  }>
}

interface PaymentData {
  installmentOptions: InstallmentOption[]
  paymentSystems: PaymentSystem[]
  payments: any[]
  giftCards: any[]
  giftCardMessages: any[]
  availableAccounts: any[]
  availableTokens: any[]
  availableAssociations: any
}

interface RatesAndBenefitsData {
  rateAndBenefitsIdentifiers: Array<{
    id: string
    name: string
    featured: boolean
    description: string
    additionalInfo?: {
      key: string
      value: string
    }
  }>
  teaser: Array<{
    featured: boolean
    id: string
    name: string
    generalValues: {
      key: string
      value: string
    }
    conditions: {
      parameters: Array<{
        name: string
        value: string
      }>
      minimumQuantity: number
    }
    effects: {
      parameters: Array<{
        name: string
        value: string
      }>
    }
    teaserType: string
  }>
}

```


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

[User] Show me the implementation of store-graphql/node/typings/ItemMetadata.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
/**
 * Assembly options related types
 */

interface CompositionItem {
  id: string
  minQuantity: number
  maxQuantity: number
  initialQuantity: number
  priceTable: string
  seller: string
}

interface Composition {
  minQuantity: number
  maxQuantity: number
  items: CompositionItem[]
}

interface AssemblyOption {
  id: string
  name: string
  composition: Composition | null
}

interface CatalogMetadataItem {
  Name: string
  NameComplete: string
  MainImage: string
  BrandName: string
  CategoryId: number
  ProductId: number
  id: string
  seller: string
  assemblyOptions: AssemblyOption[]
}

interface MetadataItem {
  id: string
  name: string
  imageUrl: string
  detailUrl: string
  seller: string
  assemblyOptions: AssemblyOption[]
  skuName: string
  productId: string
  refId: string
  ean: string | null
}
interface AddedItem {
  choiceType: string
  compositionItem: CompositionItem
  extraQuantity: number
  item: OrderFormItem
  normalizedQuantity: number
}

interface RemovedItem {
  initialQuantity: number
  name: string
  removedQuantity: number
}

```


[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 store-graphql/node/typings/Session.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Session {
  id: string
  namespaces?: {
    profile: SessionProfile
    impersonate: SessionImpersonate
    authentication: SessionAuthentication
    public: SessionPublic
  }
}

interface SessionProfile {
  id?: ObjValue
  email?: ObjValue
  firstName?: ObjValue
  lastName?: ObjValue
  phone?: ObjValue
  isAuthenticated?: ObjValue
  priceTables?: ObjValue
}

interface SessionImpersonate {
  storeUserEmail?: ObjValue
  storeUserId?: ObjValue
}

interface SessionAuthentication {
  [key: string]: string
}

interface ObjValue {
  value: string
}

interface SessionPublic {
  orderFormId?: ObjValue
  utm_source?: ObjValue
  utm_medium?: ObjValue
  utm_campaign?: ObjValue
  utm_term?: ObjValue
  utm_content?: ObjValue
  utmi_cp?: ObjValue
  utmi_pc?: ObjValue
  utmi_p?: ObjValue
}

```


[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 store-graphql/node/typings/Catalog.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface SearchArgs {
  query: string | null
  category: string | null
  specificationFilters: string[] | null
  priceRange: string | null
  collection: string | null
  salesChannel: string | null
  orderBy: string | null
  from: number | null
  to: number | null
  map: string | null
  hideUnavailableItems: boolean | null
}

interface Metadata {
  metaTagDescription?: string
  titleTag?: string
}

interface Brand {
  id: string
  name: string
  isActive: boolean
  title?: string
  metaTagDescription?: string
}

interface Category {
  id: number
  name: string
  url: string
  hasChildren: boolean
  children: Category[]
  MetaTagDescription: string
  Title: string
}

interface FacetsArgs {
  facets: string // deprecated!
  query: string
  map: string
  hideUnavailableItems: boolean
}

interface Product {
  productId: string
  productName: string
  brand: string
  brandId: number
  linkText: string
  productReference: string
  categoryId: string
  productTitle: string
  metaTagDescription: string
  clusterHighlights: Record<string, string>
  productClusters: Record<string, string>
  searchableClusters: Record<string, string>
  categories: string[]
  categoriesIds: string[]
  link: string
  description: string
  items: Item[]
  itemMetadata: {
    items: CatalogMetadataItem[]
  }
  titleTag: string
  jsonSpecifications: string
}

interface Item {
  itemId: string
  name: string
  nameComplete: string
  complementName: string
  ean: string
  referenceId: Array<{ Key: string; Value: string }>
  measurementUnit: string
  unitMultiplier: number
  modalType: any | null
  images: Array<{
    imageId: string
    imageLabel: string | null
    imageTag: string
    imageUrl: string
    imageText: string
  }>
  videos: Array<{
    videoUrl: string
  }>
  variations: string[]
  sellers: Seller[]
}

interface Installment {
  Value: number
  InterestRate: number
  TotalValuePlusInterestRate: number
  NumberOfInstallments: number
  PaymentSystemName: string
  PaymentSystemGroupName: string
  Name: string
}

// TODO: It should be Commercial, but there are so many places with this typo that I prefer to keep
interface CommertialOffer {
  DeliverySlaSamplesPerRegion: Record<
    string,
    { DeliverySlaPerTypes: any[]; Region: any | null }
  >
  Installments: Installment[]
  DiscountHighLight: any[]
  GiftSkuIds: string[]
  Teasers: any[]
  BuyTogether: any[]
  ItemMetadataAttachment: any[]
  Price: number
  PriceWithPriceTags: number
  ListPrice: number
  PriceWithoutDiscount: number
  RewardValue: number
  PriceValidUntil: string
  AvailableQuantity: number
  Tax: number
  DeliverySlaSamples: Array<{
    DeliverySlaPerTypes: any[]
    Region: any | null
  }>
  GetInfoErrorMessage: any | null
  CacheVersionUsedToCallCheckout: string
}

interface Seller {
  sellerId: string
  sellerName: string
  addToCartLink: string
  sellerDefault: boolean
  commertialOffer: CommertialOffer
}

interface SalesChannelAvailable {
  Id: number
  Name: string
  IsActive: boolean
  ProductClusterId: string | null
  CountryCode: string
  CultureInfo: string
  TimeZone: string
  CurrencyCode: string
  CurrencySymbol: string
  CurrencyLocale: number
  CurrencyFormatInfo: unknown
  Position: number
  ConditionRule: string | null
  CurrencyDecimalDigits: null | number
}

```


[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 store-graphql/node/utils/calculatePrice.ts from the store-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const calculatePrice = (
  unitMultiplier: number,
  sellingPrice: number,
  price: number
) => {
  const minRange = (sellingPrice * 10 - 1) / (unitMultiplier * 10)
  const maxRange = (sellingPrice * 10 + 9) / (unitMultiplier * 10)

  const ceilMinRange = Math.ceil(minRange)

  // Check if the Price attends the rule for items without discount
  // Avoinding unnecessary calculation

  const realPriceFromPrice = price * unitMultiplier

  if (Math.trunc(realPriceFromPrice) === sellingPrice) {
    return price
  }

  // The real price must always be a number that, when multiplied by the multiplier unit,
  // must generate a value that, when truncated to two decimal places, results in the selling price
  // We try to find a value of two decimal places and if it is not possible, we pull the first value that meets

  const realPrice =
    ceilMinRange < maxRange &&
    ceilMinRange !== minRange &&
    ceilMinRange * unitMultiplier > sellingPrice
      ? ceilMinRange
      : Number(((minRange + maxRange) / 2).toFixed(1))

  return realPrice
}

```