@faststore/api 1.7.32 → 1.7.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/api.cjs.development.js +313 -181
  3. package/dist/api.cjs.development.js.map +1 -1
  4. package/dist/api.cjs.production.min.js +1 -1
  5. package/dist/api.cjs.production.min.js.map +1 -1
  6. package/dist/api.esm.js +313 -181
  7. package/dist/api.esm.js.map +1 -1
  8. package/dist/index.d.ts +27 -13
  9. package/dist/platforms/vtex/clients/index.d.ts +4 -1
  10. package/dist/platforms/vtex/clients/search/index.d.ts +3 -3
  11. package/dist/platforms/vtex/clients/search/types/AttributeSearchResult.d.ts +25 -51
  12. package/dist/platforms/vtex/clients/search/types/FacetSearchResult.d.ts +31 -0
  13. package/dist/platforms/vtex/clients/search/types/ProductSearchResult.d.ts +146 -154
  14. package/dist/platforms/vtex/clients/sp/index.d.ts +13 -0
  15. package/dist/platforms/vtex/index.d.ts +28 -14
  16. package/dist/platforms/vtex/resolvers/aggregateOffer.d.ts +10 -6
  17. package/dist/platforms/vtex/resolvers/facet.d.ts +2 -2
  18. package/dist/platforms/vtex/resolvers/facetValue.d.ts +2 -2
  19. package/dist/platforms/vtex/resolvers/offer.d.ts +7 -6
  20. package/dist/platforms/vtex/resolvers/product.d.ts +11 -2
  21. package/dist/platforms/vtex/resolvers/productGroup.d.ts +5 -2
  22. package/dist/platforms/vtex/utils/enhanceSku.d.ts +3 -3
  23. package/dist/platforms/vtex/utils/price.d.ts +2 -0
  24. package/dist/platforms/vtex/utils/productStock.d.ts +5 -0
  25. package/dist/typings/index.d.ts +2 -0
  26. package/package.json +2 -2
  27. package/src/platforms/vtex/clients/fetch.ts +1 -1
  28. package/src/platforms/vtex/clients/index.ts +3 -0
  29. package/src/platforms/vtex/clients/search/index.ts +6 -6
  30. package/src/platforms/vtex/clients/search/types/AttributeSearchResult.ts +24 -53
  31. package/src/platforms/vtex/clients/search/types/FacetSearchResult.ts +33 -0
  32. package/src/platforms/vtex/clients/search/types/ProductSearchResult.ts +135 -164
  33. package/src/platforms/vtex/clients/sp/index.ts +67 -0
  34. package/src/platforms/vtex/index.ts +2 -2
  35. package/src/platforms/vtex/loaders/sku.ts +2 -2
  36. package/src/platforms/vtex/resolvers/aggregateOffer.ts +17 -35
  37. package/src/platforms/vtex/resolvers/facet.ts +5 -5
  38. package/src/platforms/vtex/resolvers/facetValue.ts +7 -6
  39. package/src/platforms/vtex/resolvers/offer.ts +107 -17
  40. package/src/platforms/vtex/resolvers/product.ts +55 -73
  41. package/src/platforms/vtex/resolvers/productGroup.ts +22 -13
  42. package/src/platforms/vtex/resolvers/query.ts +3 -3
  43. package/src/platforms/vtex/resolvers/searchResult.ts +24 -12
  44. package/src/platforms/vtex/utils/enhanceSku.ts +4 -4
  45. package/src/platforms/vtex/utils/facets.ts +8 -2
  46. package/src/platforms/vtex/utils/price.ts +10 -0
  47. package/src/platforms/vtex/utils/productStock.ts +25 -0
  48. package/src/typings/index.ts +4 -0
@@ -4,7 +4,7 @@ export const fetchAPI = async (info: RequestInfo, init?: RequestInit) => {
4
4
  const response = await fetch(info, init)
5
5
 
6
6
  if (response.ok) {
7
- return response.json()
7
+ return response.status !== 204 ? response.json() : undefined
8
8
  }
9
9
 
10
10
  console.error(info, init, response)
@@ -1,5 +1,6 @@
1
1
  import { VtexCommerce } from './commerce'
2
2
  import { IntelligentSearch } from './search'
3
+ import { SP } from './sp'
3
4
  import type { Context, Options } from '..'
4
5
 
5
6
  export type Clients = ReturnType<typeof getClients>
@@ -7,9 +8,11 @@ export type Clients = ReturnType<typeof getClients>
7
8
  export const getClients = (options: Options, ctx: Context) => {
8
9
  const search = IntelligentSearch(options, ctx)
9
10
  const commerce = VtexCommerce(options, ctx)
11
+ const sp = SP(options, ctx)
10
12
 
11
13
  return {
12
14
  search,
13
15
  commerce,
16
+ sp,
14
17
  }
15
18
  }
@@ -2,7 +2,7 @@ import type { Context, Options } from '../../index'
2
2
  import { fetchAPI } from '../fetch'
3
3
  import type { SelectedFacet } from '../../utils/facets'
4
4
  import type { ProductSearchResult } from './types/ProductSearchResult'
5
- import type { AttributeSearchResult } from './types/AttributeSearchResult'
5
+ import type { FacetSearchResult } from './types/FacetSearchResult'
6
6
  import type { IStoreSelectedFacet } from '../../../../__generated__/schema'
7
7
 
8
8
  export type Sort =
@@ -19,7 +19,7 @@ export interface SearchArgs {
19
19
  query?: string
20
20
  page: number
21
21
  count: number
22
- type: 'product_search' | 'attribute_search'
22
+ type: 'product_search' | 'facets'
23
23
  sort?: Sort
24
24
  selectedFacets?: SelectedFacet[]
25
25
  fuzzy?: '0' | '1'
@@ -35,7 +35,7 @@ export const IntelligentSearch = (
35
35
  { account, environment, hideUnavailableItems }: Options,
36
36
  ctx: Context
37
37
  ) => {
38
- const base = `http://portal.${environment}.com.br/search-api/v1/${account}`
38
+ const base = `https://${account}.${environment}.com.br/api/io`
39
39
  const policyFacet: IStoreSelectedFacet = {
40
40
  key: 'trade-policy',
41
41
  value: ctx.storage.channel.salesChannel,
@@ -69,7 +69,7 @@ export const IntelligentSearch = (
69
69
  })
70
70
 
71
71
  if (hideUnavailableItems !== undefined) {
72
- params.append('hide-unavailable-items', hideUnavailableItems.toString())
72
+ params.append('hideUnavailableItems', hideUnavailableItems.toString())
73
73
  }
74
74
 
75
75
  const pathname = addDefaultFacets(selectedFacets)
@@ -77,7 +77,7 @@ export const IntelligentSearch = (
77
77
  .join('/')
78
78
 
79
79
  return fetchAPI(
80
- `${base}/api/split/${type}/${pathname}?${params.toString()}`
80
+ `${base}/_v/api/intelligent-search/${type}/${pathname}?${params.toString()}`
81
81
  )
82
82
  }
83
83
 
@@ -85,7 +85,7 @@ export const IntelligentSearch = (
85
85
  search<ProductSearchResult>({ ...args, type: 'product_search' })
86
86
 
87
87
  const facets = (args: Omit<SearchArgs, 'type'>) =>
88
- search<AttributeSearchResult>({ ...args, type: 'attribute_search' })
88
+ search<FacetSearchResult>({ ...args, type: 'facets' })
89
89
 
90
90
  return {
91
91
  facets,
@@ -1,61 +1,32 @@
1
- export interface AttributeSearchResult {
2
- total: number
3
- pagination: Pagination
4
- sampling: boolean
5
- translated: boolean
6
- locale: string
7
- query: string
8
- operator: string
9
- fuzzy: string
10
- attributes: Attribute[] | null
1
+ type FilterType = 'PRICERANGE' | 'TEXT' | 'NUMBER' | 'CATEGORYTREE'
2
+ export interface FacetSearchResult {
3
+ facets: Facet[]
4
+ breadcrumb: Breadcrumb
11
5
  }
12
6
 
13
- export interface Attribute {
14
- ids: string[]
15
- visible: boolean
16
- values: Value[]
17
- active: boolean
18
- key: string
19
- originalKey: string
20
- label: string
21
- originalLabel: string
22
- type: string
23
- minValue?: number
24
- maxValue?: number
25
- templateURL?: string
26
- proxyURL?: string
7
+ export interface Facet {
8
+ type: FilterType
9
+ name: string
10
+ hidden: boolean
11
+ values: FacetValue[]
12
+ quantity?: number
27
13
  }
28
14
 
29
- export interface Value {
30
- count: number
31
- active: boolean
32
- key?: string
33
- label?: string
15
+ interface FacetValue {
16
+ quantity: number
17
+ name: string
18
+ key: string
19
+ value: string
20
+ selected?: boolean
21
+ range?: {
22
+ from: number
23
+ to: number
24
+ }
25
+ children?: FacetValue[]
34
26
  id?: string
35
- originalKey?: string
36
- originalLabel?: string
37
- proxyURL: string
38
- from?: string
39
- to?: string
40
- }
41
-
42
- export interface Pagination {
43
- count: number
44
- current: Current
45
- before: any[]
46
- after: any[]
47
- perPage: number
48
- next: First
49
- previous: First
50
- first: First
51
- last: First
52
- }
53
-
54
- export interface Current {
55
- index: number
56
- proxyURL: string
57
27
  }
58
28
 
59
- export interface First {
60
- index: number
29
+ interface Breadcrumb {
30
+ href: string
31
+ name: string
61
32
  }
@@ -0,0 +1,33 @@
1
+ type FilterType = 'PRICERANGE' | 'TEXT' | 'NUMBER' | 'CATEGORYTREE'
2
+ export interface FacetSearchResult {
3
+ facets: Facet[]
4
+ breadcrumb: Breadcrumb
5
+ }
6
+
7
+ export interface Facet {
8
+ type: FilterType
9
+ name: string
10
+ hidden: boolean
11
+ values: FacetValue[]
12
+ quantity?: number
13
+ key?: string
14
+ }
15
+
16
+ export interface FacetValue {
17
+ quantity: number
18
+ name: string
19
+ key: string
20
+ value: string
21
+ selected?: boolean
22
+ range?: {
23
+ from: number
24
+ to: number
25
+ }
26
+ children?: FacetValue[]
27
+ id?: string
28
+ }
29
+
30
+ interface Breadcrumb {
31
+ href: string
32
+ name: string
33
+ }
@@ -1,5 +1,8 @@
1
1
  export interface ProductSearchResult {
2
- total: number
2
+ /**
3
+ * @description Total of products.
4
+ */
5
+ recordsFiltered: number
3
6
  products: Product[]
4
7
  pagination: Pagination
5
8
  sampling: boolean
@@ -7,217 +10,185 @@ export interface ProductSearchResult {
7
10
  translated: boolean
8
11
  locale: string
9
12
  query: string
10
- operator: string
13
+ operator: 'and' | 'or'
11
14
  fuzzy: string
12
15
  correction: Correction
13
16
  }
14
17
 
15
- export interface Correction {
18
+ interface Correction {
16
19
  misspelled: boolean
17
20
  }
18
21
 
19
- export interface Options {
22
+ interface Options {
20
23
  sorts: Sort[]
21
24
  counts: Count[]
22
25
  }
23
26
 
24
- export interface Count {
27
+ interface Count {
25
28
  count: number
26
29
  proxyURL: string
27
30
  }
28
31
 
29
- export interface Sort {
32
+ interface Sort {
30
33
  field: string
31
34
  order: string
32
35
  active?: boolean
33
36
  proxyURL: string
34
37
  }
35
38
 
36
- export interface Pagination {
39
+ interface Pagination {
37
40
  count: number
38
- current: Current
39
- before: any[]
40
- after: Current[]
41
+ current: Page
42
+ before: Page[]
43
+ after: Page[]
41
44
  perPage: number
42
- next: Current
43
- previous: First
44
- first: First
45
- last: Current
45
+ next: Page
46
+ previous: Page
47
+ first: Page
48
+ last: Page
46
49
  }
47
50
 
48
- export interface Current {
51
+ interface Page {
49
52
  index: number
50
53
  proxyURL: string
51
54
  }
52
55
 
53
- export interface First {
54
- index: number
55
- }
56
-
57
56
  export interface Product {
58
- unitMultiplier: number
59
- year: number
60
- extraData: ExtraDatum[]
61
- release: number
62
- discount: number
63
- reference: string
64
- split: Split
65
- collections: Collection[]
66
- price: number
67
- customSort: number
68
- stickers: Sticker[]
69
- id: string
70
- stock: number
57
+ productId: string
58
+ productName: string
71
59
  brand: string
72
- availableTradePolicies: string[]
73
- categoryTrees: CategoryTree[]
74
- images: Image[]
75
- locationAttributes: any[]
76
- tax: number
77
- productScore: number
78
- storeSplitAttribute: string
79
- brandID: string
80
- installment: Installment
81
- name: string
82
- boost: Boost
83
- skus: Sku[]
60
+ brandId: number
61
+ cacheId?: string
62
+ linkText: string
63
+ productReference: string
64
+ categoryId: string
65
+ clusterHighlights: Record<string, any>
66
+ productClusters: Record<string, string>
67
+ categories: string[]
68
+ categoriesIds: string[]
84
69
  link: string
85
- wear: number
86
70
  description: string
87
- showIfNotAvailable: boolean
88
- clusterHighlights: ClusterHighlights
89
- categories: string[]
90
- timestamp: number
91
- product: string
92
- oldPrice: number
93
- productSpecifications: string[]
94
- url: string
71
+ /**
72
+ * @description Product SKUs.
73
+ */
74
+ items: Item[]
75
+ skuSpecifications?: SkuSpecification[]
76
+ priceRange: PriceRange
77
+ specificationGroups: SpecificationGroup
78
+ properties: Array<{ name: string; values: string[] }>
79
+ selectedProperties: Array<{ key: string; value: string }>
80
+ }
81
+
82
+ interface Image {
83
+ imageId: string
84
+ imageLabel: string | null
85
+ imageTag: string
86
+ imageUrl: string
87
+ imageText: string
88
+ }
89
+
90
+ interface Installment {
91
+ Value: number
92
+ InterestRate: number
93
+ TotalValuePlusInterestRate: number
94
+ NumberOfInstallments: number
95
+ PaymentSystemName: string
96
+ PaymentSystemGroupName: string
97
+ Name: string
98
+ }
99
+
100
+ export interface Item {
101
+ itemId: string
102
+ name: string
103
+ nameComplete: string
104
+ complementName: string
105
+ ean: string
106
+ referenceId: Array<{ Key: string; Value: string }>
95
107
  measurementUnit: string
96
- categoryIDS: string[]
97
- textAttributes: TextAttribute[]
98
- numberAttributes: NumberAttribute[]
99
- headSku: string
100
- specificationGroups: string
101
- extraInfo: ExtraInfo
102
- oldPriceText: string
103
- priceText: string
104
- }
105
-
106
- export interface Boost {
107
- newness: number
108
- image: number
109
- revenue: number
110
- discount: number
111
- productScore: number
112
- click: number
113
- availableSpecsCount: number
114
- promotion: number
115
- order: number
116
- }
117
-
118
- export interface CategoryTree {
119
- categoryNames: string[]
120
- categoryIDS: string[]
121
- }
122
-
123
- export interface ClusterHighlights {
124
- the140: string
125
- }
126
-
127
- export interface Collection {
128
- id: string
129
- position: number
108
+ unitMultiplier: number
109
+ modalType: any | null
110
+ images: Image[]
111
+ Videos: string[]
112
+ variations: string[]
113
+ sellers: Seller[]
114
+ attachments: Array<{
115
+ id: number
116
+ name: string
117
+ required: boolean
118
+ domainValues: string
119
+ }>
120
+ isKit: boolean
121
+ kitItems?: Array<{
122
+ itemId: string
123
+ amount: number
124
+ }>
125
+ }
126
+
127
+ export interface CommertialOffer {
128
+ DeliverySlaSamplesPerRegion: Record<
129
+ string,
130
+ { DeliverySlaPerTypes: any[]; Region: any | null }
131
+ >
132
+ Installments: Installment[]
133
+ DiscountHighLight: any[]
134
+ GiftSkuIds: string[]
135
+ Teasers: Array<Record<string, unknown>>
136
+ teasers?: Array<Record<string, unknown>>
137
+ BuyTogether: any[]
138
+ ItemMetadataAttachment: any[]
139
+ Price: number
140
+ ListPrice: number
141
+ spotPrice?: number
142
+ PriceWithoutDiscount: number
143
+ RewardValue: number
144
+ PriceValidUntil: string
145
+ AvailableQuantity: number
146
+ Tax: number
147
+ DeliverySlaSamples: Array<{
148
+ DeliverySlaPerTypes: any[]
149
+ Region: any | null
150
+ }>
151
+ GetInfoErrorMessage: any | null
152
+ CacheVersionUsedToCallCheckout: string
130
153
  }
131
154
 
132
- export interface ExtraDatum {
133
- value: string
134
- key: string
155
+ export interface Seller {
156
+ sellerId: string
157
+ sellerName: string
158
+ addToCartLink: string
159
+ sellerDefault: boolean
160
+ commertialOffer: CommertialOffer
135
161
  }
136
162
 
137
- export interface ExtraInfo {
138
- sellerID: string
163
+ interface SkuSpecification {
164
+ field: SKUSpecificationField
165
+ values: SKUSpecificationValue[]
139
166
  }
140
-
141
- export interface Image {
167
+ interface SKUSpecificationValue {
142
168
  name: string
143
- value: string
144
- }
145
-
146
- export interface Installment {
147
- interest: boolean
148
- count: number
149
- paymentGroupName: string
150
- value: number
151
- paymentName: string
152
- valueText?: string
153
- }
154
-
155
- export interface NumberAttribute {
156
- labelKey: string
157
- value: number
158
- key: string
169
+ id?: string
170
+ fieldId?: string
171
+ originalName?: string
159
172
  }
160
173
 
161
- export interface Sku {
162
- images: Image[]
163
- nameComplete: string
164
- complementName: string
165
- policies: Policy[]
166
- videos: any[]
167
- reference: string
168
- idWithSplit: string
169
- ean: string
174
+ interface SKUSpecificationField {
170
175
  name: string
171
- attributes: ExtraDatum[]
172
- id: string
173
- sellers: Seller[]
176
+ originalName?: string
177
+ id?: string
174
178
  }
175
179
 
176
- export interface Policy {
177
- id: string
178
- sellers: Seller[]
179
- }
180
-
181
- export interface Seller {
182
- default: boolean
183
- oldPrice?: number
184
- price?: number
185
- installment?: Installment
186
- name: string
187
- tax: number
188
- teasers: any[]
189
- id: string
180
+ interface Price {
181
+ highPrice: number | null
182
+ lowPrice: number | null
190
183
  }
191
184
 
192
- export interface Split {
193
- labelValue: string
194
- labelKey: string
185
+ interface PriceRange {
186
+ sellingPrice: Price
187
+ listPrice: Price
195
188
  }
196
189
 
197
- export interface Sticker {
198
- image: string
190
+ interface SpecificationGroup {
199
191
  name: string
200
- location: string
201
- target: string
202
- }
203
-
204
- export interface TextAttribute {
205
- joinedValue: string
206
- isSku: boolean
207
- joinedKey: string
208
- joinedKeyTranslations: JoinedTranslations
209
- isFilter: boolean
210
- labelValue: string
211
- id: string[]
212
- labelKey: string
213
- value: string
214
- key: string
215
- joinedValueTranslations: JoinedTranslations
216
- valueID?: string
217
- }
218
-
219
- export interface JoinedTranslations {
220
- spanish: string
221
- english: string
222
- italian: string
192
+ originalName: string
193
+ specifications: { name: string; originalName: string; values: string[] }
223
194
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Client for SP, Intelligent search's analytics event API
3
+ * More info at: https://www.notion.so/vtexhandbook/Event-API-Documentation-48eee26730cf4d7f80f8fd7262231f84
4
+ */
5
+ import { fetchAPI } from '../fetch'
6
+ import type { Options, Context } from '../../index'
7
+
8
+ const THIRTY_MINUTES_S = 30 * 60
9
+ const ONE_YEAR_S = 365 * 24 * 3600
10
+
11
+ const randomUUID = () => (Math.random() * 1e6).toFixed(0)
12
+
13
+ const timelapsed = (past: number) => (Date.now() - past) / 1e3
14
+
15
+ const createId = (expiresSecond: number) => {
16
+ let payload = randomUUID()
17
+ let createdAt = Date.now()
18
+
19
+ return () => {
20
+ if (timelapsed(createdAt) > expiresSecond) {
21
+ payload = randomUUID()
22
+ createdAt = Date.now()
23
+ }
24
+
25
+ return payload
26
+ }
27
+ }
28
+
29
+ const user = {
30
+ anonymous: createId(ONE_YEAR_S),
31
+ session: createId(THIRTY_MINUTES_S),
32
+ }
33
+
34
+ export type SearchEvent = {
35
+ type: 'search.query'
36
+ text: string // 'zapatilha'
37
+ misspelled: boolean
38
+ match: number
39
+ operator: 'and' | 'or'
40
+ session?: string
41
+ anonymous?: string
42
+ }
43
+
44
+ export const SP = ({ account }: Options, _: Context) => {
45
+ const base = `https://sp.vtex.com/event-api/v1/${account}/event`
46
+
47
+ const sendEvent = (options: SearchEvent) => {
48
+ return fetchAPI(base, {
49
+ method: 'POST',
50
+ body: JSON.stringify({
51
+ ...options,
52
+ agent: '@faststore/api',
53
+ anonymous: user.anonymous(),
54
+ session: user.session(),
55
+ // session: 'zZlNhqz1vFJP6iPG5Oqtt',
56
+ // anonymous: 'Om1TNluGvgmSgU5OOTvkkd',
57
+ }),
58
+ headers: {
59
+ 'content-type': 'application/json',
60
+ },
61
+ })
62
+ }
63
+
64
+ return {
65
+ sendEvent,
66
+ }
67
+ }
@@ -42,12 +42,12 @@ export interface Context {
42
42
  headers: Record<string, string>
43
43
  }
44
44
 
45
- export type Resolver<R = unknown, A = unknown> = (
45
+ export type Resolver<R = unknown, A = unknown, Return = any> = (
46
46
  root: R,
47
47
  args: A,
48
48
  ctx: Context,
49
49
  info: any
50
- ) => any
50
+ ) => Return
51
51
 
52
52
  const Resolvers = {
53
53
  StoreCollection,
@@ -28,8 +28,8 @@ export const getSkuLoader = (_: Options, clients: Clients) => {
28
28
  })
29
29
 
30
30
  const skuBySkuId = products.reduce((acc, product) => {
31
- for (const sku of product.skus) {
32
- acc[sku.id] = enhanceSku(sku, product)
31
+ for (const sku of product.items) {
32
+ acc[sku.itemId] = enhanceSku(sku, product)
33
33
  }
34
34
 
35
35
  return acc