@faststore/api 1.10.4 → 1.10.17
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.
- package/CHANGELOG.md +30 -0
- package/dist/api.cjs.development.js +102 -4
- package/dist/api.cjs.development.js.map +1 -1
- package/dist/api.cjs.production.min.js +1 -1
- package/dist/api.cjs.production.min.js.map +1 -1
- package/dist/api.esm.js +102 -4
- package/dist/api.esm.js.map +1 -1
- package/dist/platforms/vtex/clients/commerce/index.d.ts +13 -0
- package/dist/platforms/vtex/clients/commerce/types/Product.d.ts +174 -0
- package/dist/platforms/vtex/clients/commerce/types/SalesChannel.d.ts +24 -0
- package/dist/platforms/vtex/clients/index.d.ts +8 -0
- package/dist/platforms/vtex/loaders/index.d.ts +1 -0
- package/dist/platforms/vtex/loaders/salesChannel.d.ts +5 -0
- package/dist/platforms/vtex/resolvers/query.d.ts +3 -3
- package/dist/platforms/vtex/utils/facets.d.ts +14 -0
- package/package.json +3 -3
- package/src/platforms/vtex/clients/commerce/index.ts +27 -1
- package/src/platforms/vtex/clients/commerce/types/Product.ts +199 -0
- package/src/platforms/vtex/clients/commerce/types/SalesChannel.ts +25 -0
- package/src/platforms/vtex/loaders/index.ts +3 -0
- package/src/platforms/vtex/loaders/salesChannel.ts +15 -0
- package/src/platforms/vtex/resolvers/aggregateOffer.ts +10 -1
- package/src/platforms/vtex/resolvers/offer.ts +10 -1
- package/src/platforms/vtex/resolvers/query.ts +39 -14
- package/src/platforms/vtex/utils/facets.ts +41 -0
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { FACET_CROSS_SELLING_MAP } from "./../utils/facets"
|
|
2
|
+
import { BadRequestError, NotFoundError } from "../../errors"
|
|
3
|
+
import { mutateChannelContext, mutateLocaleContext } from "../utils/contex"
|
|
4
|
+
import { enhanceSku } from "../utils/enhanceSku"
|
|
4
5
|
import {
|
|
5
6
|
findChannel,
|
|
7
|
+
findCrossSelling,
|
|
6
8
|
findLocale,
|
|
7
9
|
findSkuId,
|
|
8
10
|
findSlug,
|
|
9
11
|
transformSelectedFacet,
|
|
10
|
-
} from
|
|
11
|
-
import { SORT_MAP } from
|
|
12
|
-
import { StoreCollection } from
|
|
12
|
+
} from "../utils/facets"
|
|
13
|
+
import { SORT_MAP } from "../utils/sort"
|
|
14
|
+
import { StoreCollection } from "./collection"
|
|
13
15
|
import type {
|
|
14
|
-
QueryProductArgs,
|
|
15
16
|
QueryAllCollectionsArgs,
|
|
16
17
|
QueryAllProductsArgs,
|
|
17
|
-
QuerySearchArgs,
|
|
18
18
|
QueryCollectionArgs,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import {
|
|
19
|
+
QueryProductArgs,
|
|
20
|
+
QuerySearchArgs,
|
|
21
|
+
} from "../../../__generated__/schema"
|
|
22
|
+
import type { CategoryTree } from "../clients/commerce/types/CategoryTree"
|
|
23
|
+
import type { Context } from "../index"
|
|
24
|
+
import { isValidSkuId, pickBestSku } from "../utils/sku"
|
|
23
25
|
|
|
24
26
|
export const Query = {
|
|
25
27
|
product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => {
|
|
@@ -95,6 +97,7 @@ export const Query = {
|
|
|
95
97
|
// Insert channel in context for later usage
|
|
96
98
|
const channel = findChannel(selectedFacets)
|
|
97
99
|
const locale = findLocale(selectedFacets)
|
|
100
|
+
const crossSelling = findCrossSelling(selectedFacets)
|
|
98
101
|
|
|
99
102
|
if (channel) {
|
|
100
103
|
mutateChannelContext(ctx, channel)
|
|
@@ -104,11 +107,33 @@ export const Query = {
|
|
|
104
107
|
mutateLocaleContext(ctx, locale)
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
let query = term
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* In case we are using crossSelling, we need to modify the search
|
|
114
|
+
* we will be performing on our search engine. The idea in here
|
|
115
|
+
* is to use the cross selling API for fetching the productIds our
|
|
116
|
+
* search will return for us.
|
|
117
|
+
* Doing this two request workflow makes it possible to have cross
|
|
118
|
+
* selling with Search features, like pagination, internationalization
|
|
119
|
+
* etc
|
|
120
|
+
*/
|
|
121
|
+
if (crossSelling) {
|
|
122
|
+
const products = await ctx.clients.commerce.catalog.products.crossselling({
|
|
123
|
+
type: FACET_CROSS_SELLING_MAP[crossSelling.key],
|
|
124
|
+
productId: crossSelling.value,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
query = `product:${
|
|
128
|
+
products.map((x) => x.productId).slice(0, first).join(";")
|
|
129
|
+
}`
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
const after = maybeAfter ? Number(maybeAfter) : 0
|
|
108
133
|
const searchArgs = {
|
|
109
|
-
page: Math.ceil(after / first
|
|
134
|
+
page: Math.ceil(after / first),
|
|
110
135
|
count: first,
|
|
111
|
-
query
|
|
136
|
+
query,
|
|
112
137
|
sort: SORT_MAP[sort ?? 'score_desc'],
|
|
113
138
|
selectedFacets: selectedFacets?.flatMap(transformSelectedFacet) ?? [],
|
|
114
139
|
}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import ChannelMarshal from './channel'
|
|
2
2
|
import type { Maybe } from '../../../__generated__/schema'
|
|
3
|
+
import { BadRequestError } from '../../errors'
|
|
3
4
|
|
|
4
5
|
export interface SelectedFacet {
|
|
5
6
|
key: string
|
|
6
7
|
value: string
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
export interface CrossSellingFacet {
|
|
11
|
+
key: keyof typeof FACET_CROSS_SELLING_MAP
|
|
12
|
+
value: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const FACET_CROSS_SELLING_MAP = {
|
|
16
|
+
buy: "whoboughtalsobought",
|
|
17
|
+
view: "whosawalsosaw",
|
|
18
|
+
similars: "similars",
|
|
19
|
+
viewAndBought: "whosawalsobought",
|
|
20
|
+
accessories: "accessories",
|
|
21
|
+
suggestions: "suggestions",
|
|
22
|
+
} as const
|
|
23
|
+
|
|
9
24
|
/**
|
|
10
25
|
* Transform facets from the store to VTEX platform facets.
|
|
11
26
|
* For instance, the channel in Store becomes trade-policy and regionId in VTEX's realm
|
|
@@ -33,6 +48,15 @@ export const transformSelectedFacet = ({ key, value }: SelectedFacet) => {
|
|
|
33
48
|
return { key, value: value.replace('-to-', ':') }
|
|
34
49
|
}
|
|
35
50
|
|
|
51
|
+
case "buy":
|
|
52
|
+
case "view":
|
|
53
|
+
case "similars":
|
|
54
|
+
case "viewAndBought":
|
|
55
|
+
case "accessories":
|
|
56
|
+
case "suggestions": {
|
|
57
|
+
return [] // remove this facet from search
|
|
58
|
+
}
|
|
59
|
+
|
|
36
60
|
default:
|
|
37
61
|
return { key, value }
|
|
38
62
|
}
|
|
@@ -52,6 +76,23 @@ export const parseRange = (range: string): [number, number] | null => {
|
|
|
52
76
|
return splitted as [number, number]
|
|
53
77
|
}
|
|
54
78
|
|
|
79
|
+
export const isCrossSelling = (
|
|
80
|
+
x: string,
|
|
81
|
+
): x is CrossSellingFacet['key'] =>
|
|
82
|
+
typeof (FACET_CROSS_SELLING_MAP as Record<string, string>)[x] === "string"
|
|
83
|
+
|
|
84
|
+
export const findCrossSelling = (facets?: Maybe<SelectedFacet[]>) => {
|
|
85
|
+
const filtered = facets?.filter((x): x is CrossSellingFacet => isCrossSelling(x.key))
|
|
86
|
+
|
|
87
|
+
if (Array.isArray(filtered) && filtered.length > 1) {
|
|
88
|
+
throw new BadRequestError(
|
|
89
|
+
`You passed ${filtered.length} cross selling facets but only one is allowed. Please leave one of the following facet: ${filtered.map(x => x.key).join(',')}`
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return filtered?.[0] ?? null
|
|
94
|
+
}
|
|
95
|
+
|
|
55
96
|
export const findSlug = (facets?: Maybe<SelectedFacet[]>) =>
|
|
56
97
|
facets?.find((x) => x.key === 'slug')?.value ?? null
|
|
57
98
|
|