@faststore/api 1.9.14 → 1.10.6

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.
@@ -1,3 +1,5 @@
1
+ import { FACET_CROSS_SELLING_MAP } from "../../utils/facets";
2
+ import type { PortalProduct } from "./types/Product";
1
3
  import type { Context, Options } from '../../index';
2
4
  import type { Brand } from './types/Brand';
3
5
  import type { CategoryTree } from './types/CategoryTree';
@@ -7,6 +9,7 @@ import type { Region, RegionInput } from './types/Region';
7
9
  import type { Simulation, SimulationArgs, SimulationOptions } from './types/Simulation';
8
10
  import type { Session } from './types/Session';
9
11
  import type { Channel } from '../../utils/channel';
12
+ declare type ValueOf<T> = T extends Record<string, infer K> ? K : never;
10
13
  export declare const VtexCommerce: ({ account, environment }: Options, ctx: Context) => {
11
14
  catalog: {
12
15
  brand: {
@@ -18,6 +21,13 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
18
21
  portal: {
19
22
  pagetype: (slug: string) => Promise<PortalPagetype>;
20
23
  };
24
+ products: {
25
+ crossselling: ({ type, productId, groupByProduct }: {
26
+ type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
27
+ productId: string;
28
+ groupByProduct?: boolean | undefined;
29
+ }) => Promise<PortalProduct[]>;
30
+ };
21
31
  };
22
32
  checkout: {
23
33
  simulation: (args: SimulationArgs, { salesChannel }?: SimulationOptions) => Promise<Simulation>;
@@ -42,3 +52,4 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
42
52
  };
43
53
  session: (search: string) => Promise<Session>;
44
54
  };
55
+ export {};
@@ -0,0 +1,174 @@
1
+ export interface PortalProduct {
2
+ productId: string;
3
+ productName: string;
4
+ brand: string;
5
+ brandId: number;
6
+ brandImageUrl: null | string;
7
+ linkText: string;
8
+ productReference: string;
9
+ productReferenceCode: string;
10
+ categoryId: string;
11
+ productTitle: string;
12
+ metaTagDescription: string;
13
+ releaseDate: Date;
14
+ clusterHighlights: unknown;
15
+ productClusters: unknown;
16
+ searchableClusters: unknown;
17
+ categories: Category[];
18
+ categoriesIds: CategoriesId[];
19
+ link: string;
20
+ description: string;
21
+ items: Item[];
22
+ }
23
+ declare enum Category {
24
+ Office = "/Office/",
25
+ OfficeChairs = "/Office/Chairs/"
26
+ }
27
+ declare enum CategoriesId {
28
+ The9282 = "/9282/",
29
+ The92829296 = "/9282/9296/"
30
+ }
31
+ interface Item {
32
+ itemId: string;
33
+ name: string;
34
+ nameComplete: string;
35
+ complementName: string;
36
+ ean: string;
37
+ referenceId: ReferenceId[];
38
+ measurementUnit: MeasurementUnit;
39
+ unitMultiplier: number;
40
+ modalType: null;
41
+ isKit: boolean;
42
+ images: Image[];
43
+ sellers: Seller[];
44
+ videos: unknown[];
45
+ estimatedDateArrival: null;
46
+ }
47
+ interface Image {
48
+ imageId: string;
49
+ imageLabel: string;
50
+ imageTag: string;
51
+ imageUrl: string;
52
+ imageText: string;
53
+ imageLastModified: Date;
54
+ }
55
+ declare enum MeasurementUnit {
56
+ Un = "un"
57
+ }
58
+ interface ReferenceId {
59
+ key: Key;
60
+ value: string;
61
+ }
62
+ declare enum Key {
63
+ RefId = "RefId"
64
+ }
65
+ interface Seller {
66
+ sellerId: string;
67
+ sellerName: SellerName;
68
+ addToCartLink: string;
69
+ sellerDefault: boolean;
70
+ commertialOffer: CommertialOffer;
71
+ }
72
+ interface CommertialOffer {
73
+ deliverySlaSamplesPerRegion: DeliverySlaSamplesPerRegion;
74
+ installments: Installment[];
75
+ discountHighLight: unknown[];
76
+ giftSkuIds: unknown[];
77
+ teasers: unknown[];
78
+ buyTogether: unknown[];
79
+ itemMetadataAttachment: unknown[];
80
+ price: number;
81
+ listPrice: number;
82
+ priceWithoutDiscount: number;
83
+ rewardValue: number;
84
+ priceValidUntil: Date;
85
+ availableQuantity: number;
86
+ isAvailable: boolean;
87
+ tax: number;
88
+ deliverySlaSamples: DeliverySlaSample[];
89
+ getInfoErrorMessage: null;
90
+ cacheVersionUsedToCallCheckout: string;
91
+ paymentOptions: PaymentOptions;
92
+ }
93
+ interface DeliverySlaSample {
94
+ deliverySlaPerTypes: unknown[];
95
+ region: null;
96
+ }
97
+ interface DeliverySlaSamplesPerRegion {
98
+ the0: DeliverySlaSample;
99
+ }
100
+ interface Installment {
101
+ value: number;
102
+ interestRate: number;
103
+ totalValuePlusInterestRate: number;
104
+ numberOfInstallments: number;
105
+ paymentSystemName: PaymentSystemNameEnum;
106
+ paymentSystemGroupName: GroupName;
107
+ name: Name;
108
+ }
109
+ declare enum Name {
110
+ BoletoBancárioÀVista = "Boleto Banc\u00E1rio \u00E0 vista",
111
+ FreeÀVista = "Free \u00E0 vista"
112
+ }
113
+ declare enum GroupName {
114
+ BankInvoicePaymentGroup = "bankInvoicePaymentGroup",
115
+ Custom201PaymentGroupPaymentGroup = "custom201PaymentGroupPaymentGroup"
116
+ }
117
+ declare enum PaymentSystemNameEnum {
118
+ BoletoBancário = "Boleto Banc\u00E1rio",
119
+ Free = "Free"
120
+ }
121
+ interface PaymentOptions {
122
+ installmentOptions: InstallmentOption[];
123
+ paymentSystems: PaymentSystem[];
124
+ payments: unknown[];
125
+ giftCards: unknown[];
126
+ giftCardMessages: unknown[];
127
+ availableAccounts: unknown[];
128
+ availableTokens: unknown[];
129
+ }
130
+ interface InstallmentOption {
131
+ paymentSystem: string;
132
+ bin: null;
133
+ paymentName: PaymentSystemNameEnum;
134
+ paymentGroupName: GroupName;
135
+ value: number;
136
+ installments: InstallmentElement[];
137
+ }
138
+ interface InstallmentElement {
139
+ count: number;
140
+ hasInterestRate: boolean;
141
+ interestRate: number;
142
+ value: number;
143
+ total: number;
144
+ sellerMerchantInstallments?: InstallmentElement[];
145
+ id?: Id;
146
+ }
147
+ declare enum Id {
148
+ Storeframework = "STOREFRAMEWORK"
149
+ }
150
+ interface PaymentSystem {
151
+ id: number;
152
+ name: PaymentSystemNameEnum;
153
+ groupName: GroupName;
154
+ validator: null;
155
+ stringId: string;
156
+ template: Template;
157
+ requiresDocument: boolean;
158
+ isCustom: boolean;
159
+ description: Description | null;
160
+ requiresAuthentication: boolean;
161
+ dueDate: Date;
162
+ availablePayments: null;
163
+ }
164
+ declare enum Description {
165
+ FreePayToTestCheckoutPayments = "Free pay to test checkout payments"
166
+ }
167
+ declare enum Template {
168
+ BankInvoicePaymentGroupTemplate = "bankInvoicePaymentGroup-template",
169
+ Custom201PaymentGroupPaymentGroupTemplate = "custom201PaymentGroupPaymentGroup-template"
170
+ }
171
+ declare enum SellerName {
172
+ Vtex = "VTEX"
173
+ }
174
+ export {};
@@ -18,6 +18,13 @@ export declare const getClients: (options: Options, ctx: Context) => {
18
18
  portal: {
19
19
  pagetype: (slug: string) => Promise<import("./commerce/types/Portal").PortalPagetype>;
20
20
  };
21
+ products: {
22
+ crossselling: ({ type, productId, groupByProduct }: {
23
+ type: "whoboughtalsobought" | "whosawalsosaw" | "similars" | "whosawalsobought" | "accessories" | "suggestions";
24
+ productId: string;
25
+ groupByProduct?: boolean | undefined;
26
+ }) => Promise<import("./commerce/types/Product").PortalProduct[]>;
27
+ };
21
28
  };
22
29
  checkout: {
23
30
  simulation: (args: import("./commerce/types/Simulation").SimulationArgs, { salesChannel }?: import("./commerce/types/Simulation").SimulationOptions) => Promise<import("./commerce/types/Simulation").Simulation>;
@@ -1,6 +1,6 @@
1
- import type { QueryProductArgs, QueryAllCollectionsArgs, QueryAllProductsArgs, QuerySearchArgs, QueryCollectionArgs } from '../../../__generated__/schema';
2
- import type { CategoryTree } from '../clients/commerce/types/CategoryTree';
3
- import type { Context } from '../index';
1
+ import type { QueryAllCollectionsArgs, QueryAllProductsArgs, QueryCollectionArgs, QueryProductArgs, QuerySearchArgs } from "../../../__generated__/schema";
2
+ import type { CategoryTree } from "../clients/commerce/types/CategoryTree";
3
+ import type { Context } from "../index";
4
4
  export declare const Query: {
5
5
  product: (_: unknown, { locator }: QueryProductArgs, ctx: Context) => Promise<import("../utils/enhanceSku").EnhancedSku>;
6
6
  collection: (_: unknown, { slug }: QueryCollectionArgs, ctx: Context) => Promise<import("../clients/commerce/types/Portal").CollectionPageType>;
@@ -2,6 +2,18 @@ export interface SelectedFacet {
2
2
  key: string;
3
3
  value: string;
4
4
  }
5
+ export interface CrossSellingFacet {
6
+ key: keyof typeof FACET_CROSS_SELLING_MAP;
7
+ value: string;
8
+ }
9
+ export declare const FACET_CROSS_SELLING_MAP: {
10
+ readonly buy: "whoboughtalsobought";
11
+ readonly view: "whosawalsosaw";
12
+ readonly similars: "similars";
13
+ readonly viewAndBought: "whosawalsobought";
14
+ readonly accessories: "accessories";
15
+ readonly suggestions: "suggestions";
16
+ };
5
17
  /**
6
18
  * Transform facets from the store to VTEX platform facets.
7
19
  * For instance, the channel in Store becomes trade-policy and regionId in VTEX's realm
@@ -14,6 +26,8 @@ export declare const transformSelectedFacet: ({ key, value }: SelectedFacet) =>
14
26
  value: string;
15
27
  };
16
28
  export declare const parseRange: (range: string) => [number, number] | null;
29
+ export declare const isCrossSelling: (x: string) => x is "similars" | "accessories" | "suggestions" | "buy" | "view" | "viewAndBought";
30
+ export declare const findCrossSelling: (facets?: SelectedFacet[] | null | undefined) => CrossSellingFacet | null;
17
31
  export declare const findSlug: (facets?: SelectedFacet[] | null | undefined) => string | null;
18
32
  export declare const findSkuId: (facets?: SelectedFacet[] | null | undefined) => string | null;
19
33
  export declare const findLocale: (facets?: SelectedFacet[] | null | undefined) => string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/api",
3
- "version": "1.9.14",
3
+ "version": "1.10.6",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "express-graphql": "^0.12.0",
38
38
  "graphql": "^15.6.0",
39
39
  "jest-transform-graphql": "^2.1.0",
40
- "shared": "^1.9.14",
40
+ "shared": "^1.10.6",
41
41
  "ts-jest": "25.5.1",
42
42
  "tsdx": "^0.14.1",
43
43
  "tslib": "^2.3.1",
@@ -46,5 +46,5 @@
46
46
  "peerDependencies": {
47
47
  "graphql": "^15.6.0"
48
48
  },
49
- "gitHead": "d37facb5b238781bb18ce48afb1b245e5c53038b"
49
+ "gitHead": "654744a6c3b29afacbd83c4d9ebefe4270d1ae2a"
50
50
  }
@@ -341,8 +341,9 @@ export type StoreFacetRange = {
341
341
  key: Scalars['String'];
342
342
  /** Facet label. */
343
343
  label: Scalars['String'];
344
+ /** Maximum facet range value. */
344
345
  max: StoreFacetValueRange;
345
- /** Array with information on each facet value. */
346
+ /** Minimum facet range value. */
346
347
  min: StoreFacetValueRange;
347
348
  };
348
349
 
@@ -367,9 +368,12 @@ export type StoreFacetValueBoolean = {
367
368
  value: Scalars['String'];
368
369
  };
369
370
 
371
+ /** Search facet range value information. Used for minimum and maximum range values. */
370
372
  export type StoreFacetValueRange = {
371
373
  __typename?: 'StoreFacetValueRange';
374
+ /** Search facet range absolute value. */
372
375
  absolute: Scalars['Float'];
376
+ /** Search facet range selected value. */
373
377
  selected: Scalars['Float'];
374
378
  };
375
379
 
@@ -1,4 +1,6 @@
1
- import { fetchAPI } from '../fetch'
1
+ import { FACET_CROSS_SELLING_MAP } from "../../utils/facets"
2
+ import { fetchAPI } from "../fetch"
3
+ import type { PortalProduct } from "./types/Product"
2
4
  import type { Context, Options } from '../../index'
3
5
  import type { Brand } from './types/Brand'
4
6
  import type { CategoryTree } from './types/CategoryTree'
@@ -13,6 +15,8 @@ import type {
13
15
  import type { Session } from './types/Session'
14
16
  import type { Channel } from '../../utils/channel'
15
17
 
18
+ type ValueOf<T> = T extends Record<string, infer K> ? K : never;
19
+
16
20
  const BASE_INIT = {
17
21
  method: 'POST',
18
22
  headers: {
@@ -40,6 +44,24 @@ export const VtexCommerce = (
40
44
  pagetype: (slug: string): Promise<PortalPagetype> =>
41
45
  fetchAPI(`${base}/api/catalog_system/pub/portal/pagetype/${slug}`),
42
46
  },
47
+ products: {
48
+ crossselling: (
49
+ { type, productId, groupByProduct = true }: {
50
+ type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
51
+ productId: string;
52
+ groupByProduct?: boolean;
53
+ },
54
+ ): Promise<PortalProduct[]> => {
55
+ const params = new URLSearchParams({
56
+ sc: ctx.storage.channel.salesChannel,
57
+ groupByProduct: groupByProduct.toString(),
58
+ })
59
+
60
+ return fetchAPI(
61
+ `${base}/api/catalog_system/pub/products/crossselling/${type}/${productId}?${params}`,
62
+ )
63
+ },
64
+ },
43
65
  },
44
66
  checkout: {
45
67
  simulation: (
@@ -120,7 +142,7 @@ export const VtexCommerce = (
120
142
  ...BASE_INIT,
121
143
  body: JSON.stringify({ value }),
122
144
  method: 'PUT',
123
- }
145
+ },
124
146
  )
125
147
  },
126
148
  region: async ({
@@ -0,0 +1,199 @@
1
+ export interface PortalProduct {
2
+ productId: string;
3
+ productName: string;
4
+ brand: string;
5
+ brandId: number;
6
+ brandImageUrl: null | string;
7
+ linkText: string;
8
+ productReference: string;
9
+ productReferenceCode: string;
10
+ categoryId: string;
11
+ productTitle: string;
12
+ metaTagDescription: string;
13
+ releaseDate: Date;
14
+ clusterHighlights: unknown;
15
+ productClusters: unknown;
16
+ searchableClusters: unknown;
17
+ categories: Category[];
18
+ categoriesIds: CategoriesId[];
19
+ link: string;
20
+ description: string;
21
+ items: Item[];
22
+ }
23
+
24
+ enum Category {
25
+ Office = "/Office/",
26
+ OfficeChairs = "/Office/Chairs/",
27
+ }
28
+
29
+ enum CategoriesId {
30
+ The9282 = "/9282/",
31
+ The92829296 = "/9282/9296/",
32
+ }
33
+
34
+
35
+
36
+ interface Item {
37
+ itemId: string;
38
+ name: string;
39
+ nameComplete: string;
40
+ complementName: string;
41
+ ean: string;
42
+ referenceId: ReferenceId[];
43
+ measurementUnit: MeasurementUnit;
44
+ unitMultiplier: number;
45
+ modalType: null;
46
+ isKit: boolean;
47
+ images: Image[];
48
+ sellers: Seller[];
49
+ videos: unknown[];
50
+ estimatedDateArrival: null;
51
+ }
52
+
53
+ interface Image {
54
+ imageId: string;
55
+ imageLabel: string;
56
+ imageTag: string;
57
+ imageUrl: string;
58
+ imageText: string;
59
+ imageLastModified: Date;
60
+ }
61
+
62
+ enum MeasurementUnit {
63
+ Un = "un",
64
+ }
65
+
66
+ interface ReferenceId {
67
+ key: Key;
68
+ value: string;
69
+ }
70
+
71
+ enum Key {
72
+ RefId = "RefId",
73
+ }
74
+
75
+ interface Seller {
76
+ sellerId: string;
77
+ sellerName: SellerName;
78
+ addToCartLink: string;
79
+ sellerDefault: boolean;
80
+ commertialOffer: CommertialOffer;
81
+ }
82
+
83
+ interface CommertialOffer {
84
+ deliverySlaSamplesPerRegion: DeliverySlaSamplesPerRegion;
85
+ installments: Installment[];
86
+ discountHighLight: unknown[];
87
+ giftSkuIds: unknown[];
88
+ teasers: unknown[];
89
+ buyTogether: unknown[];
90
+ itemMetadataAttachment: unknown[];
91
+ price: number;
92
+ listPrice: number;
93
+ priceWithoutDiscount: number;
94
+ rewardValue: number;
95
+ priceValidUntil: Date;
96
+ availableQuantity: number;
97
+ isAvailable: boolean;
98
+ tax: number;
99
+ deliverySlaSamples: DeliverySlaSample[];
100
+ getInfoErrorMessage: null;
101
+ cacheVersionUsedToCallCheckout: string;
102
+ paymentOptions: PaymentOptions;
103
+ }
104
+
105
+ interface DeliverySlaSample {
106
+ deliverySlaPerTypes: unknown[];
107
+ region: null;
108
+ }
109
+
110
+ interface DeliverySlaSamplesPerRegion {
111
+ the0: DeliverySlaSample;
112
+ }
113
+
114
+ interface Installment {
115
+ value: number;
116
+ interestRate: number;
117
+ totalValuePlusInterestRate: number;
118
+ numberOfInstallments: number;
119
+ paymentSystemName: PaymentSystemNameEnum;
120
+ paymentSystemGroupName: GroupName;
121
+ name: Name;
122
+ }
123
+
124
+ enum Name {
125
+ BoletoBancárioÀVista = "Boleto Bancário à vista",
126
+ FreeÀVista = "Free à vista",
127
+ }
128
+
129
+ enum GroupName {
130
+ BankInvoicePaymentGroup = "bankInvoicePaymentGroup",
131
+ Custom201PaymentGroupPaymentGroup = "custom201PaymentGroupPaymentGroup",
132
+ }
133
+
134
+ enum PaymentSystemNameEnum {
135
+ BoletoBancário = "Boleto Bancário",
136
+ Free = "Free",
137
+ }
138
+
139
+ interface PaymentOptions {
140
+ installmentOptions: InstallmentOption[];
141
+ paymentSystems: PaymentSystem[];
142
+ payments: unknown[];
143
+ giftCards: unknown[];
144
+ giftCardMessages: unknown[];
145
+ availableAccounts: unknown[];
146
+ availableTokens: unknown[];
147
+ }
148
+
149
+ interface InstallmentOption {
150
+ paymentSystem: string;
151
+ bin: null;
152
+ paymentName: PaymentSystemNameEnum;
153
+ paymentGroupName: GroupName;
154
+ value: number;
155
+ installments: InstallmentElement[];
156
+ }
157
+
158
+ interface InstallmentElement {
159
+ count: number;
160
+ hasInterestRate: boolean;
161
+ interestRate: number;
162
+ value: number;
163
+ total: number;
164
+ sellerMerchantInstallments?: InstallmentElement[];
165
+ id?: Id;
166
+ }
167
+
168
+ enum Id {
169
+ Storeframework = "STOREFRAMEWORK",
170
+ }
171
+
172
+ interface PaymentSystem {
173
+ id: number;
174
+ name: PaymentSystemNameEnum;
175
+ groupName: GroupName;
176
+ validator: null;
177
+ stringId: string;
178
+ template: Template;
179
+ requiresDocument: boolean;
180
+ isCustom: boolean;
181
+ description: Description | null;
182
+ requiresAuthentication: boolean;
183
+ dueDate: Date;
184
+ availablePayments: null;
185
+ }
186
+
187
+ enum Description {
188
+ FreePayToTestCheckoutPayments = "Free pay to test checkout payments",
189
+ }
190
+
191
+ enum Template {
192
+ BankInvoicePaymentGroupTemplate = "bankInvoicePaymentGroup-template",
193
+ Custom201PaymentGroupPaymentGroupTemplate =
194
+ "custom201PaymentGroupPaymentGroup-template",
195
+ }
196
+
197
+ enum SellerName {
198
+ Vtex = "VTEX",
199
+ }
@@ -1,25 +1,27 @@
1
- import { NotFoundError, BadRequestError } from '../../errors'
2
- import { mutateChannelContext, mutateLocaleContext } from '../utils/contex'
3
- import { enhanceSku } from '../utils/enhanceSku'
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 '../utils/facets'
11
- import { SORT_MAP } from '../utils/sort'
12
- import { StoreCollection } from './collection'
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
- } from '../../../__generated__/schema'
20
- import type { CategoryTree } from '../clients/commerce/types/CategoryTree'
21
- import type { Context } from '../index'
22
- import { isValidSkuId, pickBestSku } from '../utils/sku'
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: term,
136
+ query,
112
137
  sort: SORT_MAP[sort ?? 'score_desc'],
113
138
  selectedFacets: selectedFacets?.flatMap(transformSelectedFacet) ?? [],
114
139
  }