@faststore/api 1.9.6 → 1.9.9
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 +519 -1691
- package/README.md +5 -2
- package/dist/__generated__/schema.d.ts +49 -33
- package/dist/api.cjs.development.js +129 -50
- 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 +129 -50
- package/dist/api.esm.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/platforms/vtex/clients/commerce/types/Portal.d.ts +1 -1
- package/dist/platforms/vtex/index.d.ts +5 -4
- package/dist/platforms/vtex/loaders/index.d.ts +1 -1
- package/dist/platforms/vtex/loaders/sku.d.ts +1 -2
- package/dist/platforms/vtex/resolvers/mutation.d.ts +3 -3
- package/dist/platforms/vtex/resolvers/offer.d.ts +1 -1
- package/dist/platforms/vtex/resolvers/seo.d.ts +1 -0
- package/dist/platforms/vtex/resolvers/validateCart.d.ts +3 -3
- package/dist/platforms/vtex/utils/canonical.d.ts +2 -0
- package/dist/platforms/vtex/utils/facets.d.ts +2 -0
- package/dist/platforms/vtex/utils/orderStatistics.d.ts +4 -0
- package/dist/platforms/vtex/utils/sku.d.ts +8 -0
- package/package.json +3 -2
- package/src/__generated__/schema.ts +49 -33
- package/src/platforms/vtex/clients/commerce/index.ts +1 -1
- package/src/platforms/vtex/clients/commerce/types/Portal.ts +1 -1
- package/src/platforms/vtex/index.ts +12 -10
- package/src/platforms/vtex/loaders/sku.ts +3 -16
- package/src/platforms/vtex/resolvers/offer.ts +6 -3
- package/src/platforms/vtex/resolvers/product.ts +6 -4
- package/src/platforms/vtex/resolvers/query.ts +44 -1
- package/src/platforms/vtex/resolvers/seo.ts +2 -2
- package/src/platforms/vtex/resolvers/validateCart.ts +3 -3
- package/src/platforms/vtex/utils/canonical.ts +3 -0
- package/src/platforms/vtex/utils/facets.ts +6 -0
- package/src/platforms/vtex/utils/orderStatistics.ts +16 -0
- package/src/platforms/vtex/utils/sku.ts +26 -0
- package/src/typeDefs/cart.graphql +1 -1
- package/src/typeDefs/collection.graphql +12 -0
- package/src/typeDefs/mutation.graphql +2 -2
- package/src/typeDefs/order.graphql +1 -1
- package/src/typeDefs/pageInfo.graphql +5 -5
- package/src/typeDefs/query.graphql +59 -23
- package/src/typeDefs/session.graphql +4 -4
- package/src/typeDefs/status.graphql +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export declare const getResolvers: (options: Options) => {
|
|
|
49
49
|
StoreSeo: Record<string, import("./platforms/vtex").Resolver<{
|
|
50
50
|
title?: string | undefined;
|
|
51
51
|
description?: string | undefined;
|
|
52
|
+
canonical?: string | undefined;
|
|
52
53
|
}, unknown, any>>;
|
|
53
54
|
StoreFacet: Record<string, import("./platforms/vtex").Resolver<import("./platforms/vtex/clients/search/types/FacetSearchResult").Facet, unknown, any>>;
|
|
54
55
|
StoreFacetValue: Record<string, import("./platforms/vtex").Resolver<import("./platforms/vtex/clients/search/types/FacetSearchResult").FacetValue, unknown, any>>;
|
|
@@ -57,7 +58,7 @@ export declare const getResolvers: (options: Options) => {
|
|
|
57
58
|
} & {
|
|
58
59
|
attachmentsValues?: import("./platforms/vtex/clients/commerce/types/OrderForm").Attachment[] | undefined;
|
|
59
60
|
}> | (import("./platforms/vtex/clients/commerce/types/OrderForm").OrderFormItem & {
|
|
60
|
-
product:
|
|
61
|
+
product: import("./platforms/vtex/utils/enhanceSku").EnhancedSku;
|
|
61
62
|
}), unknown, any>>;
|
|
62
63
|
StoreAggregateRating: Record<string, import("./platforms/vtex").Resolver<unknown, unknown, any>>;
|
|
63
64
|
StoreReview: Record<string, import("./platforms/vtex").Resolver<unknown, unknown, any>>;
|
|
@@ -125,8 +126,8 @@ export declare const getResolvers: (options: Options) => {
|
|
|
125
126
|
}, ctx: import("./platforms/vtex").Context) => Promise<{
|
|
126
127
|
order: {
|
|
127
128
|
orderNumber: string;
|
|
128
|
-
acceptedOffer: {
|
|
129
|
-
product:
|
|
129
|
+
acceptedOffer: Promise<{
|
|
130
|
+
product: import("./platforms/vtex/utils/enhanceSku").EnhancedSku;
|
|
130
131
|
id: string;
|
|
131
132
|
name: string;
|
|
132
133
|
detailUrl: string;
|
|
@@ -170,7 +171,7 @@ export declare const getResolvers: (options: Options) => {
|
|
|
170
171
|
total: number;
|
|
171
172
|
};
|
|
172
173
|
attachments: import("./platforms/vtex/clients/commerce/types/OrderForm").Attachment[];
|
|
173
|
-
}[];
|
|
174
|
+
}>[];
|
|
174
175
|
};
|
|
175
176
|
messages: {
|
|
176
177
|
text: any;
|
|
@@ -5,7 +5,7 @@ export interface CollectionPageType {
|
|
|
5
5
|
url: string;
|
|
6
6
|
title: string;
|
|
7
7
|
metaTagDescription: string;
|
|
8
|
-
pageType: 'Brand' | 'Category' | 'Department' | 'Subcategory';
|
|
8
|
+
pageType: 'Brand' | 'Category' | 'Department' | 'Subcategory' | 'Product';
|
|
9
9
|
}
|
|
10
10
|
export interface FallbackPageType {
|
|
11
11
|
id: null;
|
|
@@ -77,6 +77,7 @@ export declare const getResolvers: (_: Options) => {
|
|
|
77
77
|
StoreSeo: Record<string, Resolver<{
|
|
78
78
|
title?: string | undefined;
|
|
79
79
|
description?: string | undefined;
|
|
80
|
+
canonical?: string | undefined;
|
|
80
81
|
}, unknown, any>>;
|
|
81
82
|
StoreFacet: Record<string, Resolver<import("./clients/search/types/FacetSearchResult").Facet, unknown, any>>;
|
|
82
83
|
StoreFacetValue: Record<string, Resolver<import("./clients/search/types/FacetSearchResult").FacetValue, unknown, any>>;
|
|
@@ -85,7 +86,7 @@ export declare const getResolvers: (_: Options) => {
|
|
|
85
86
|
} & {
|
|
86
87
|
attachmentsValues?: import("./clients/commerce/types/OrderForm").Attachment[] | undefined;
|
|
87
88
|
}> | (import("./clients/commerce/types/OrderForm").OrderFormItem & {
|
|
88
|
-
product:
|
|
89
|
+
product: import("./utils/enhanceSku").EnhancedSku;
|
|
89
90
|
}), unknown, any>>;
|
|
90
91
|
StoreAggregateRating: Record<string, Resolver<unknown, unknown, any>>;
|
|
91
92
|
StoreReview: Record<string, Resolver<unknown, unknown, any>>;
|
|
@@ -153,8 +154,8 @@ export declare const getResolvers: (_: Options) => {
|
|
|
153
154
|
}, ctx: Context) => Promise<{
|
|
154
155
|
order: {
|
|
155
156
|
orderNumber: string;
|
|
156
|
-
acceptedOffer: {
|
|
157
|
-
product:
|
|
157
|
+
acceptedOffer: Promise<{
|
|
158
|
+
product: import("./utils/enhanceSku").EnhancedSku;
|
|
158
159
|
id: string;
|
|
159
160
|
name: string;
|
|
160
161
|
detailUrl: string;
|
|
@@ -198,7 +199,7 @@ export declare const getResolvers: (_: Options) => {
|
|
|
198
199
|
total: number;
|
|
199
200
|
};
|
|
200
201
|
attachments: import("./clients/commerce/types/OrderForm").Attachment[];
|
|
201
|
-
}[];
|
|
202
|
+
}>[];
|
|
202
203
|
};
|
|
203
204
|
messages: {
|
|
204
205
|
text: any;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Context, Options } from '..';
|
|
2
2
|
export declare type Loaders = ReturnType<typeof getLoaders>;
|
|
3
3
|
export declare const getLoaders: (options: Options, { clients }: Context) => {
|
|
4
|
-
skuLoader: import("dataloader")<
|
|
4
|
+
skuLoader: import("dataloader")<string, import("../utils/enhanceSku").EnhancedSku, string>;
|
|
5
5
|
simulationLoader: import("dataloader")<import("../clients/commerce/types/Simulation").PayloadItem[], import("../clients/commerce/types/Simulation").Simulation, import("../clients/commerce/types/Simulation").PayloadItem[]>;
|
|
6
6
|
collectionLoader: import("dataloader")<string, import("../clients/commerce/types/Portal").CollectionPageType, string>;
|
|
7
7
|
};
|
|
@@ -2,5 +2,4 @@ import DataLoader from 'dataloader';
|
|
|
2
2
|
import type { EnhancedSku } from '../utils/enhanceSku';
|
|
3
3
|
import type { Options } from '..';
|
|
4
4
|
import type { Clients } from '../clients';
|
|
5
|
-
|
|
6
|
-
export declare const getSkuLoader: (_: Options, clients: Clients) => DataLoader<SelectedFacet[], EnhancedSku, SelectedFacet[]>;
|
|
5
|
+
export declare const getSkuLoader: (_: Options, clients: Clients) => DataLoader<string, EnhancedSku, string>;
|
|
@@ -4,8 +4,8 @@ export declare const Mutation: {
|
|
|
4
4
|
}, ctx: import("..").Context) => Promise<{
|
|
5
5
|
order: {
|
|
6
6
|
orderNumber: string;
|
|
7
|
-
acceptedOffer: {
|
|
8
|
-
product:
|
|
7
|
+
acceptedOffer: Promise<{
|
|
8
|
+
product: import("../utils/enhanceSku").EnhancedSku;
|
|
9
9
|
id: string;
|
|
10
10
|
name: string;
|
|
11
11
|
detailUrl: string;
|
|
@@ -49,7 +49,7 @@ export declare const Mutation: {
|
|
|
49
49
|
total: number;
|
|
50
50
|
};
|
|
51
51
|
attachments: import("../clients/commerce/types/OrderForm").Attachment[];
|
|
52
|
-
}[];
|
|
52
|
+
}>[];
|
|
53
53
|
};
|
|
54
54
|
messages: {
|
|
55
55
|
text: any;
|
|
@@ -4,7 +4,7 @@ import type { ArrayElementType } from '../../../typings';
|
|
|
4
4
|
import type { EnhancedSku } from '../utils/enhanceSku';
|
|
5
5
|
import type { OrderFormItem } from '../clients/commerce/types/OrderForm';
|
|
6
6
|
declare type OrderFormProduct = OrderFormItem & {
|
|
7
|
-
product:
|
|
7
|
+
product: EnhancedSku;
|
|
8
8
|
};
|
|
9
9
|
declare type SearchProduct = ArrayElementType<ReturnType<typeof StoreAggregateOffer.offers>>;
|
|
10
10
|
declare type Root = SearchProduct | OrderFormProduct;
|
|
@@ -18,8 +18,8 @@ export declare const validateCart: (_: unknown, { cart: { order } }: {
|
|
|
18
18
|
}, ctx: Context) => Promise<{
|
|
19
19
|
order: {
|
|
20
20
|
orderNumber: string;
|
|
21
|
-
acceptedOffer: {
|
|
22
|
-
product:
|
|
21
|
+
acceptedOffer: Promise<{
|
|
22
|
+
product: import("../utils/enhanceSku").EnhancedSku;
|
|
23
23
|
id: string;
|
|
24
24
|
name: string;
|
|
25
25
|
detailUrl: string;
|
|
@@ -63,7 +63,7 @@ export declare const validateCart: (_: unknown, { cart: { order } }: {
|
|
|
63
63
|
total: number;
|
|
64
64
|
};
|
|
65
65
|
attachments: import("../clients/commerce/types/OrderForm").Attachment[];
|
|
66
|
-
}[];
|
|
66
|
+
}>[];
|
|
67
67
|
};
|
|
68
68
|
messages: {
|
|
69
69
|
text: any;
|
|
@@ -13,5 +13,7 @@ export declare const transformSelectedFacet: ({ key, value }: SelectedFacet) =>
|
|
|
13
13
|
key: string;
|
|
14
14
|
value: string;
|
|
15
15
|
};
|
|
16
|
+
export declare const findSlug: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
17
|
+
export declare const findSkuId: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
16
18
|
export declare const findLocale: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
17
19
|
export declare const findChannel: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Item } from '../clients/search/types/ProductSearchResult';
|
|
2
|
+
/**
|
|
3
|
+
* This function implements Portal heuristics for returning the best sku for a product.
|
|
4
|
+
*
|
|
5
|
+
* The best sku is the one with the best (cheapest available) offer
|
|
6
|
+
* */
|
|
7
|
+
export declare const pickBestSku: (skus: Item[]) => Item;
|
|
8
|
+
export declare const isValidSkuId: (skuId: string) => boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/api",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"develop": "tsdx watch --entry ./local/server.ts --target node --onSuccess \"node ./dist\"",
|
|
18
18
|
"develop:no-server": "concurrently \"yarn generate -w\" \"tsdx watch\"",
|
|
19
19
|
"build": "graphql-codegen --config codegen.yml && tsdx build",
|
|
20
|
+
"lint": "eslint src/**/*.ts",
|
|
20
21
|
"test": "tsdx test",
|
|
21
22
|
"generate": "graphql-codegen --config codegen.yml"
|
|
22
23
|
},
|
|
@@ -44,5 +45,5 @@
|
|
|
44
45
|
"peerDependencies": {
|
|
45
46
|
"graphql": "^15.6.0"
|
|
46
47
|
},
|
|
47
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "1f1d2c97e399fb44987cdbd7980157242f193abf"
|
|
48
49
|
}
|
|
@@ -19,9 +19,9 @@ export type IStoreCart = {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export type IStoreCurrency = {
|
|
22
|
-
/** Currency code
|
|
22
|
+
/** Currency code (e.g: USD). */
|
|
23
23
|
code: Scalars['String'];
|
|
24
|
-
/** Currency symbol
|
|
24
|
+
/** Currency symbol (e.g: $). */
|
|
25
25
|
symbol: Scalars['String'];
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -47,7 +47,7 @@ export type IStoreOffer = {
|
|
|
47
47
|
seller: IStoreOrganization;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
/**
|
|
50
|
+
/** Order input. */
|
|
51
51
|
export type IStoreOrder = {
|
|
52
52
|
/** Array with information on each accepted offer. */
|
|
53
53
|
acceptedOffer: Array<IStoreOffer>;
|
|
@@ -96,9 +96,11 @@ export type IStorePropertyValue = {
|
|
|
96
96
|
valueReference: Scalars['String'];
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
/** Selected facet input. */
|
|
99
|
+
/** Selected search facet input. */
|
|
100
100
|
export type IStoreSelectedFacet = {
|
|
101
|
+
/** Selected search facet key. */
|
|
101
102
|
key: Scalars['String'];
|
|
103
|
+
/** Selected search facet value. */
|
|
102
104
|
value: Scalars['String'];
|
|
103
105
|
};
|
|
104
106
|
|
|
@@ -120,9 +122,9 @@ export type IStoreSession = {
|
|
|
120
122
|
|
|
121
123
|
export type Mutation = {
|
|
122
124
|
__typename?: 'Mutation';
|
|
123
|
-
/**
|
|
125
|
+
/** Checks for changes between the cart presented in the UI and the cart stored in the ecommerce platform. If changes are detected, it returns the cart stored on the platform. Otherwise, it returns `null`. */
|
|
124
126
|
validateCart?: Maybe<StoreCart>;
|
|
125
|
-
/**
|
|
127
|
+
/** Updates a web session with the specified values. */
|
|
126
128
|
validateSession?: Maybe<StoreSession>;
|
|
127
129
|
};
|
|
128
130
|
|
|
@@ -139,15 +141,15 @@ export type MutationValidateSessionArgs = {
|
|
|
139
141
|
|
|
140
142
|
export type Query = {
|
|
141
143
|
__typename?: 'Query';
|
|
142
|
-
/**
|
|
144
|
+
/** Returns information about all collections. */
|
|
143
145
|
allCollections: StoreCollectionConnection;
|
|
144
|
-
/**
|
|
146
|
+
/** Returns information about all products. */
|
|
145
147
|
allProducts: StoreProductConnection;
|
|
146
|
-
/**
|
|
148
|
+
/** Returns the details of a collection based on the collection slug. */
|
|
147
149
|
collection: StoreCollection;
|
|
148
|
-
/**
|
|
150
|
+
/** Returns the details of a product based on the specified locator. */
|
|
149
151
|
product: StoreProduct;
|
|
150
|
-
/**
|
|
152
|
+
/** Returns the result of a product, facet, or suggestion search. */
|
|
151
153
|
search: StoreSearchResult;
|
|
152
154
|
};
|
|
153
155
|
|
|
@@ -241,7 +243,7 @@ export type StoreCart = {
|
|
|
241
243
|
/** Shopping cart message. */
|
|
242
244
|
export type StoreCartMessage = {
|
|
243
245
|
__typename?: 'StoreCartMessage';
|
|
244
|
-
/** Shopping cart message status, which can be `INFO`, `WARNING`
|
|
246
|
+
/** Shopping cart message status, which can be `INFO`, `WARNING` or `ERROR`. */
|
|
245
247
|
status: StoreStatus;
|
|
246
248
|
/** Shopping cart message text. */
|
|
247
249
|
text: Scalars['String'];
|
|
@@ -264,21 +266,21 @@ export type StoreCollection = {
|
|
|
264
266
|
type: StoreCollectionType;
|
|
265
267
|
};
|
|
266
268
|
|
|
267
|
-
/** Collection
|
|
269
|
+
/** Collection connections, including pagination information and collections returned by the query. */
|
|
268
270
|
export type StoreCollectionConnection = {
|
|
269
271
|
__typename?: 'StoreCollectionConnection';
|
|
270
|
-
/** Array with collection connection page edges
|
|
272
|
+
/** Array with collection connection page edges, each containing a collection and a corresponding cursor.. */
|
|
271
273
|
edges: Array<StoreCollectionEdge>;
|
|
272
|
-
/** Collection
|
|
274
|
+
/** Collection pagination information. */
|
|
273
275
|
pageInfo: StorePageInfo;
|
|
274
276
|
};
|
|
275
277
|
|
|
276
|
-
/**
|
|
278
|
+
/** Each collection edge contains a `node`, with product collection information, and a `cursor`, that can be used as a reference for pagination. */
|
|
277
279
|
export type StoreCollectionEdge = {
|
|
278
280
|
__typename?: 'StoreCollectionEdge';
|
|
279
|
-
/** Collection pagination
|
|
281
|
+
/** Collection cursor. Used as pagination reference. */
|
|
280
282
|
cursor: Scalars['String'];
|
|
281
|
-
/**
|
|
283
|
+
/** Each collection node contains the information of a product collection returned by the query. */
|
|
282
284
|
node: StoreCollection;
|
|
283
285
|
};
|
|
284
286
|
|
|
@@ -300,18 +302,22 @@ export type StoreCollectionMeta = {
|
|
|
300
302
|
|
|
301
303
|
/** Product collection type. Possible values are `Department`, `Category`, `Brand` or `Cluster`. */
|
|
302
304
|
export const enum StoreCollectionType {
|
|
305
|
+
/** Product brand. */
|
|
303
306
|
Brand = 'Brand',
|
|
307
|
+
/** Second level of product categorization. */
|
|
304
308
|
Category = 'Category',
|
|
309
|
+
/** Product cluster. */
|
|
305
310
|
Cluster = 'Cluster',
|
|
311
|
+
/** First level of product categorization. */
|
|
306
312
|
Department = 'Department'
|
|
307
313
|
};
|
|
308
314
|
|
|
309
315
|
/** Currency information. */
|
|
310
316
|
export type StoreCurrency = {
|
|
311
317
|
__typename?: 'StoreCurrency';
|
|
312
|
-
/** Currency code
|
|
318
|
+
/** Currency code (e.g: USD). */
|
|
313
319
|
code: Scalars['String'];
|
|
314
|
-
/** Currency symbol
|
|
320
|
+
/** Currency symbol (e.g: $). */
|
|
315
321
|
symbol: Scalars['String'];
|
|
316
322
|
};
|
|
317
323
|
|
|
@@ -330,7 +336,9 @@ export type StoreFacet = {
|
|
|
330
336
|
|
|
331
337
|
/** Search facet type. */
|
|
332
338
|
export const enum StoreFacetType {
|
|
339
|
+
/** Indicates boolean search facet. */
|
|
333
340
|
Boolean = 'BOOLEAN',
|
|
341
|
+
/** Indicates range type search facet. */
|
|
334
342
|
Range = 'RANGE'
|
|
335
343
|
};
|
|
336
344
|
|
|
@@ -408,16 +416,16 @@ export type StoreOrganization = {
|
|
|
408
416
|
identifier: Scalars['String'];
|
|
409
417
|
};
|
|
410
418
|
|
|
411
|
-
/**
|
|
419
|
+
/** Whenever you make a query that allows for pagination, such as `allProducts` or `allCollections`, you can check `StorePageInfo` to learn more about the complete set of items and use it to paginate your queries. */
|
|
412
420
|
export type StorePageInfo = {
|
|
413
421
|
__typename?: 'StorePageInfo';
|
|
414
|
-
/**
|
|
422
|
+
/** Cursor corresponding to the last possible item. */
|
|
415
423
|
endCursor: Scalars['String'];
|
|
416
|
-
/** Indicates whether
|
|
424
|
+
/** Indicates whether there is at least one more page with items after the ones returned in the current query. */
|
|
417
425
|
hasNextPage: Scalars['Boolean'];
|
|
418
|
-
/** Indicates whether
|
|
426
|
+
/** Indicates whether there is at least one more page with items before the ones returned in the current query. */
|
|
419
427
|
hasPreviousPage: Scalars['Boolean'];
|
|
420
|
-
/**
|
|
428
|
+
/** Cursor corresponding to the first possible item. */
|
|
421
429
|
startCursor: Scalars['String'];
|
|
422
430
|
/** Total number of items (products or collections), not pages. */
|
|
423
431
|
totalCount: Scalars['Int'];
|
|
@@ -471,21 +479,21 @@ export type StoreProduct = {
|
|
|
471
479
|
slug: Scalars['String'];
|
|
472
480
|
};
|
|
473
481
|
|
|
474
|
-
/** Product
|
|
482
|
+
/** Product connections, including pagination information and products returned by the query. */
|
|
475
483
|
export type StoreProductConnection = {
|
|
476
484
|
__typename?: 'StoreProductConnection';
|
|
477
|
-
/** Array with product connection
|
|
485
|
+
/** Array with product connection edges, each containing a product and a corresponding cursor. */
|
|
478
486
|
edges: Array<StoreProductEdge>;
|
|
479
|
-
/** Product
|
|
487
|
+
/** Product pagination information. */
|
|
480
488
|
pageInfo: StorePageInfo;
|
|
481
489
|
};
|
|
482
490
|
|
|
483
|
-
/**
|
|
491
|
+
/** Each product edge contains a `node`, with product information, and a `cursor`, that can be used as a reference for pagination. */
|
|
484
492
|
export type StoreProductEdge = {
|
|
485
493
|
__typename?: 'StoreProductEdge';
|
|
486
|
-
/** Product pagination
|
|
494
|
+
/** Product cursor. Used as pagination reference. */
|
|
487
495
|
cursor: Scalars['String'];
|
|
488
|
-
/**
|
|
496
|
+
/** Each product node contains the information of a product returned by the query. */
|
|
489
497
|
node: StoreProduct;
|
|
490
498
|
};
|
|
491
499
|
|
|
@@ -574,19 +582,27 @@ export type StoreSession = {
|
|
|
574
582
|
postalCode?: Maybe<Scalars['String']>;
|
|
575
583
|
};
|
|
576
584
|
|
|
577
|
-
/** Product sorting options
|
|
585
|
+
/** Product search results sorting options. */
|
|
578
586
|
export const enum StoreSort {
|
|
587
|
+
/** Sort by discount value, from highest to lowest. */
|
|
579
588
|
DiscountDesc = 'discount_desc',
|
|
589
|
+
/** Sort by name, in alphabetical order. */
|
|
580
590
|
NameAsc = 'name_asc',
|
|
591
|
+
/** Sort by name, in reverse alphabetical order. */
|
|
581
592
|
NameDesc = 'name_desc',
|
|
593
|
+
/** Sort by orders, from highest to lowest. */
|
|
582
594
|
OrdersDesc = 'orders_desc',
|
|
595
|
+
/** Sort by price, from lowest to highest. */
|
|
583
596
|
PriceAsc = 'price_asc',
|
|
597
|
+
/** Sort by price, from highest to lowest. */
|
|
584
598
|
PriceDesc = 'price_desc',
|
|
599
|
+
/** Sort by release date, from highest to lowest. */
|
|
585
600
|
ReleaseDesc = 'release_desc',
|
|
601
|
+
/** Sort by product score, from highest to lowest. */
|
|
586
602
|
ScoreDesc = 'score_desc'
|
|
587
603
|
};
|
|
588
604
|
|
|
589
|
-
/** Status used to indicate
|
|
605
|
+
/** Status used to indicate a message type. For instance, a shopping cart informative or error message. */
|
|
590
606
|
export const enum StoreStatus {
|
|
591
607
|
Error = 'ERROR',
|
|
592
608
|
Info = 'INFO',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Context, Options } from '../../index'
|
|
2
1
|
import { fetchAPI } from '../fetch'
|
|
2
|
+
import type { Context, Options } from '../../index'
|
|
3
3
|
import type { Brand } from './types/Brand'
|
|
4
4
|
import type { CategoryTree } from './types/CategoryTree'
|
|
5
5
|
import type { OrderForm, OrderFormInputItem } from './types/OrderForm'
|
|
@@ -6,7 +6,7 @@ export interface CollectionPageType {
|
|
|
6
6
|
url: string
|
|
7
7
|
title: string
|
|
8
8
|
metaTagDescription: string
|
|
9
|
-
pageType: 'Brand' | 'Category' | 'Department' | 'Subcategory'
|
|
9
|
+
pageType: 'Brand' | 'Category' | 'Department' | 'Subcategory' | 'Product'
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface FallbackPageType {
|
|
@@ -77,16 +77,18 @@ const Resolvers = {
|
|
|
77
77
|
Mutation,
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export const getContextFactory =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
export const getContextFactory =
|
|
81
|
+
(options: Options) =>
|
|
82
|
+
(ctx: any): Context => {
|
|
83
|
+
ctx.storage = {
|
|
84
|
+
channel: ChannelMarshal.parse(options.channel),
|
|
85
|
+
flags: options.flags ?? {},
|
|
86
|
+
locale: options.locale,
|
|
87
|
+
}
|
|
88
|
+
ctx.clients = getClients(options, ctx)
|
|
89
|
+
ctx.loaders = getLoaders(options, ctx)
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
+
return ctx
|
|
92
|
+
}
|
|
91
93
|
|
|
92
94
|
export const getResolvers = (_: Options) => Resolvers
|
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
import DataLoader from 'dataloader'
|
|
2
2
|
|
|
3
3
|
import { enhanceSku } from '../utils/enhanceSku'
|
|
4
|
-
import {
|
|
4
|
+
import { NotFoundError } from '../../errors'
|
|
5
5
|
import type { EnhancedSku } from '../utils/enhanceSku'
|
|
6
6
|
import type { Options } from '..'
|
|
7
7
|
import type { Clients } from '../clients'
|
|
8
|
-
import type { SelectedFacet } from '../utils/facets'
|
|
9
8
|
|
|
10
9
|
export const getSkuLoader = (_: Options, clients: Clients) => {
|
|
11
|
-
const loader = async (
|
|
12
|
-
const skuIds = facetsList.map((facets) => {
|
|
13
|
-
const maybeFacet = facets.find(({ key }) => key === 'id')
|
|
14
|
-
|
|
15
|
-
if (!maybeFacet) {
|
|
16
|
-
throw new BadRequestError(
|
|
17
|
-
'Error while loading SKU. Needs to pass an id to selected facets'
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return maybeFacet.value
|
|
22
|
-
})
|
|
23
|
-
|
|
10
|
+
const loader = async (skuIds: readonly string[]) => {
|
|
24
11
|
const { products } = await clients.search.products({
|
|
25
12
|
query: `sku:${skuIds.join(';')}`,
|
|
26
13
|
page: 0,
|
|
@@ -47,7 +34,7 @@ export const getSkuLoader = (_: Options, clients: Clients) => {
|
|
|
47
34
|
return skus
|
|
48
35
|
}
|
|
49
36
|
|
|
50
|
-
return new DataLoader<
|
|
37
|
+
return new DataLoader<string, EnhancedSku>(loader, {
|
|
51
38
|
maxBatchSize: 99, // Max allowed batch size of Search API
|
|
52
39
|
})
|
|
53
40
|
}
|
|
@@ -11,7 +11,7 @@ import type { ArrayElementType } from '../../../typings'
|
|
|
11
11
|
import type { EnhancedSku } from '../utils/enhanceSku'
|
|
12
12
|
import type { OrderFormItem } from '../clients/commerce/types/OrderForm'
|
|
13
13
|
|
|
14
|
-
type OrderFormProduct = OrderFormItem & { product:
|
|
14
|
+
type OrderFormProduct = OrderFormItem & { product: EnhancedSku }
|
|
15
15
|
type SearchProduct = ArrayElementType<
|
|
16
16
|
ReturnType<typeof StoreAggregateOffer.offers>
|
|
17
17
|
>
|
|
@@ -96,13 +96,16 @@ export const StoreOffer: Record<string, Resolver<Root>> = {
|
|
|
96
96
|
|
|
97
97
|
return null
|
|
98
98
|
},
|
|
99
|
-
itemOffered:
|
|
99
|
+
itemOffered: (root) => {
|
|
100
100
|
if (isSearchItem(root)) {
|
|
101
101
|
return root.product
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
if (isOrderFormItem(root)) {
|
|
105
|
-
return {
|
|
105
|
+
return {
|
|
106
|
+
...root.product,
|
|
107
|
+
attachmentsValues: root.attachments,
|
|
108
|
+
}
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
return null
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { canonicalFromProduct } from '../utils/canonical'
|
|
1
2
|
import { enhanceCommercialOffer } from '../utils/enhanceCommercialOffer'
|
|
2
3
|
import { bestOfferFirst } from '../utils/productStock'
|
|
3
4
|
import { slugify } from '../utils/slugify'
|
|
@@ -41,9 +42,10 @@ export const StoreProduct: Record<string, Resolver<Root>> & {
|
|
|
41
42
|
name: ({ isVariantOf, name }) => name ?? isVariantOf.productName,
|
|
42
43
|
slug: ({ isVariantOf: { linkText }, itemId }) => getSlug(linkText, itemId),
|
|
43
44
|
description: ({ isVariantOf: { description } }) => description,
|
|
44
|
-
seo: ({ isVariantOf
|
|
45
|
-
title: productName,
|
|
46
|
-
description,
|
|
45
|
+
seo: ({ isVariantOf }) => ({
|
|
46
|
+
title: isVariantOf.productName,
|
|
47
|
+
description: isVariantOf.description,
|
|
48
|
+
canonical: canonicalFromProduct(isVariantOf),
|
|
47
49
|
}),
|
|
48
50
|
brand: ({ isVariantOf: { brand } }) => ({ name: brand }),
|
|
49
51
|
breadcrumbList: ({
|
|
@@ -85,7 +87,7 @@ export const StoreProduct: Record<string, Resolver<Root>> & {
|
|
|
85
87
|
aggregateRating: () => ({}),
|
|
86
88
|
offers: (root) =>
|
|
87
89
|
root.sellers
|
|
88
|
-
.
|
|
90
|
+
.map((seller) =>
|
|
89
91
|
enhanceCommercialOffer({
|
|
90
92
|
offer: seller.commertialOffer,
|
|
91
93
|
seller,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { NotFoundError, BadRequestError } from '../../errors'
|
|
1
2
|
import { mutateChannelContext, mutateLocaleContext } from '../utils/contex'
|
|
2
3
|
import { enhanceSku } from '../utils/enhanceSku'
|
|
3
4
|
import {
|
|
4
5
|
findChannel,
|
|
5
6
|
findLocale,
|
|
7
|
+
findSkuId,
|
|
8
|
+
findSlug,
|
|
6
9
|
transformSelectedFacet,
|
|
7
10
|
} from '../utils/facets'
|
|
8
11
|
import { SORT_MAP } from '../utils/sort'
|
|
@@ -16,12 +19,15 @@ import type {
|
|
|
16
19
|
} from '../../../__generated__/schema'
|
|
17
20
|
import type { CategoryTree } from '../clients/commerce/types/CategoryTree'
|
|
18
21
|
import type { Context } from '../index'
|
|
22
|
+
import { isValidSkuId, pickBestSku } from '../utils/sku'
|
|
19
23
|
|
|
20
24
|
export const Query = {
|
|
21
25
|
product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => {
|
|
22
26
|
// Insert channel in context for later usage
|
|
23
27
|
const channel = findChannel(locator)
|
|
24
28
|
const locale = findLocale(locator)
|
|
29
|
+
const id = findSkuId(locator)
|
|
30
|
+
const slug = findSlug(locator)
|
|
25
31
|
|
|
26
32
|
if (channel) {
|
|
27
33
|
mutateChannelContext(ctx, channel)
|
|
@@ -33,9 +39,46 @@ export const Query = {
|
|
|
33
39
|
|
|
34
40
|
const {
|
|
35
41
|
loaders: { skuLoader },
|
|
42
|
+
clients: { commerce, search },
|
|
36
43
|
} = ctx
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
try {
|
|
46
|
+
const skuId = id ?? slug?.split('-').pop() ?? ''
|
|
47
|
+
|
|
48
|
+
if (!isValidSkuId(skuId)) {
|
|
49
|
+
throw new Error('Invalid SkuId')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sku = await skuLoader.load(skuId)
|
|
53
|
+
|
|
54
|
+
return sku
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (slug == null) {
|
|
57
|
+
throw new BadRequestError('Missing slug or id')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const route = await commerce.catalog.portal.pagetype(`${slug}/p`)
|
|
61
|
+
|
|
62
|
+
if (route.pageType !== 'Product' || !route.id) {
|
|
63
|
+
throw new NotFoundError(`No product found for slug ${slug}`)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
products: [product],
|
|
68
|
+
} = await search.products({
|
|
69
|
+
page: 0,
|
|
70
|
+
count: 1,
|
|
71
|
+
query: `product:${route.id}`,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (!product) {
|
|
75
|
+
throw new NotFoundError(`No product found for id ${route.id}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const sku = pickBestSku(product.items)
|
|
79
|
+
|
|
80
|
+
return enhanceSku(sku, product)
|
|
81
|
+
}
|
|
39
82
|
},
|
|
40
83
|
collection: (_: unknown, { slug }: QueryCollectionArgs, ctx: Context) => {
|
|
41
84
|
const {
|