@faststore/api 1.9.6 → 1.9.7

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 (33) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/api.cjs.development.js +113 -34
  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 +113 -34
  7. package/dist/api.esm.js.map +1 -1
  8. package/dist/index.d.ts +5 -4
  9. package/dist/platforms/vtex/clients/commerce/types/Portal.d.ts +1 -1
  10. package/dist/platforms/vtex/index.d.ts +5 -4
  11. package/dist/platforms/vtex/loaders/index.d.ts +1 -1
  12. package/dist/platforms/vtex/loaders/sku.d.ts +1 -2
  13. package/dist/platforms/vtex/resolvers/mutation.d.ts +3 -3
  14. package/dist/platforms/vtex/resolvers/offer.d.ts +1 -1
  15. package/dist/platforms/vtex/resolvers/seo.d.ts +1 -0
  16. package/dist/platforms/vtex/resolvers/validateCart.d.ts +3 -3
  17. package/dist/platforms/vtex/utils/canonical.d.ts +2 -0
  18. package/dist/platforms/vtex/utils/facets.d.ts +2 -0
  19. package/dist/platforms/vtex/utils/orderStatistics.d.ts +4 -0
  20. package/dist/platforms/vtex/utils/sku.d.ts +8 -0
  21. package/package.json +2 -2
  22. package/src/platforms/vtex/clients/commerce/index.ts +1 -1
  23. package/src/platforms/vtex/clients/commerce/types/Portal.ts +1 -1
  24. package/src/platforms/vtex/loaders/sku.ts +3 -16
  25. package/src/platforms/vtex/resolvers/offer.ts +6 -3
  26. package/src/platforms/vtex/resolvers/product.ts +6 -4
  27. package/src/platforms/vtex/resolvers/query.ts +44 -1
  28. package/src/platforms/vtex/resolvers/seo.ts +2 -2
  29. package/src/platforms/vtex/resolvers/validateCart.ts +3 -3
  30. package/src/platforms/vtex/utils/canonical.ts +3 -0
  31. package/src/platforms/vtex/utils/facets.ts +6 -0
  32. package/src/platforms/vtex/utils/orderStatistics.ts +16 -0
  33. package/src/platforms/vtex/utils/sku.ts +26 -0
package/dist/api.esm.js CHANGED
@@ -386,18 +386,7 @@ const isBadRequestError = error => {
386
386
  };
387
387
 
388
388
  const getSkuLoader = (_, clients) => {
389
- const loader = async facetsList => {
390
- const skuIds = facetsList.map(facets => {
391
- const maybeFacet = facets.find(({
392
- key
393
- }) => key === 'id');
394
-
395
- if (!maybeFacet) {
396
- throw new BadRequestError('Error while loading SKU. Needs to pass an id to selected facets');
397
- }
398
-
399
- return maybeFacet.value;
400
- });
389
+ const loader = async skuIds => {
401
390
  const {
402
391
  products
403
392
  } = await clients.search.products({
@@ -740,15 +729,12 @@ const equals = (storeOrder, orderForm) => {
740
729
  return isSameOrder && orderItemsAreSync;
741
730
  };
742
731
 
743
- const orderFormToCart = (form, skuLoader) => {
732
+ const orderFormToCart = async (form, skuLoader) => {
744
733
  return {
745
734
  order: {
746
735
  orderNumber: form.orderFormId,
747
- acceptedOffer: form.items.map(item => ({ ...item,
748
- product: skuLoader.load([{
749
- key: 'id',
750
- value: item.id
751
- }])
736
+ acceptedOffer: form.items.map(async item => ({ ...item,
737
+ product: await skuLoader.load(item.id)
752
738
  }))
753
739
  },
754
740
  messages: form.messages.map(({
@@ -1056,13 +1042,13 @@ const StoreOffer = {
1056
1042
 
1057
1043
  return null;
1058
1044
  },
1059
- itemOffered: async root => {
1045
+ itemOffered: root => {
1060
1046
  if (isSearchItem(root)) {
1061
1047
  return root.product;
1062
1048
  }
1063
1049
 
1064
1050
  if (isOrderFormItem(root)) {
1065
- return { ...(await root.product),
1051
+ return { ...root.product,
1066
1052
  attachmentsValues: root.attachments
1067
1053
  };
1068
1054
  }
@@ -1084,6 +1070,10 @@ const StoreOffer = {
1084
1070
  }
1085
1071
  };
1086
1072
 
1073
+ const canonicalFromProduct = ({
1074
+ linkText
1075
+ }) => `/${linkText}/p`;
1076
+
1087
1077
  const enhanceCommercialOffer = ({
1088
1078
  offer,
1089
1079
  seller,
@@ -1124,13 +1114,11 @@ const StoreProduct = {
1124
1114
  }
1125
1115
  }) => description,
1126
1116
  seo: ({
1127
- isVariantOf: {
1128
- description,
1129
- productName
1130
- }
1117
+ isVariantOf
1131
1118
  }) => ({
1132
- title: productName,
1133
- description
1119
+ title: isVariantOf.productName,
1120
+ description: isVariantOf.description,
1121
+ canonical: canonicalFromProduct(isVariantOf)
1134
1122
  }),
1135
1123
  brand: ({
1136
1124
  isVariantOf: {
@@ -1190,7 +1178,7 @@ const StoreProduct = {
1190
1178
  },
1191
1179
  review: () => [],
1192
1180
  aggregateRating: () => ({}),
1193
- offers: root => root.sellers.flatMap(seller => enhanceCommercialOffer({
1181
+ offers: root => root.sellers.map(seller => enhanceCommercialOffer({
1194
1182
  offer: seller.commertialOffer,
1195
1183
  seller,
1196
1184
  product: root
@@ -1288,15 +1276,25 @@ const transformSelectedFacet = ({
1288
1276
  };
1289
1277
  }
1290
1278
  };
1291
- const findLocale = facets => {
1279
+ const findSlug = facets => {
1292
1280
  var _facets$find$value, _facets$find;
1293
1281
 
1294
- return (_facets$find$value = facets == null ? void 0 : (_facets$find = facets.find(x => x.key === 'locale')) == null ? void 0 : _facets$find.value) != null ? _facets$find$value : null;
1282
+ return (_facets$find$value = facets == null ? void 0 : (_facets$find = facets.find(x => x.key === 'slug')) == null ? void 0 : _facets$find.value) != null ? _facets$find$value : null;
1295
1283
  };
1296
- const findChannel = facets => {
1284
+ const findSkuId = facets => {
1297
1285
  var _facets$find$value2, _facets$find2;
1298
1286
 
1299
- return (_facets$find$value2 = facets == null ? void 0 : (_facets$find2 = facets.find(facet => facet.key === 'channel')) == null ? void 0 : _facets$find2.value) != null ? _facets$find$value2 : null;
1287
+ return (_facets$find$value2 = facets == null ? void 0 : (_facets$find2 = facets.find(x => x.key === 'id')) == null ? void 0 : _facets$find2.value) != null ? _facets$find$value2 : null;
1288
+ };
1289
+ const findLocale = facets => {
1290
+ var _facets$find$value3, _facets$find3;
1291
+
1292
+ return (_facets$find$value3 = facets == null ? void 0 : (_facets$find3 = facets.find(x => x.key === 'locale')) == null ? void 0 : _facets$find3.value) != null ? _facets$find$value3 : null;
1293
+ };
1294
+ const findChannel = facets => {
1295
+ var _facets$find$value4, _facets$find4;
1296
+
1297
+ return (_facets$find$value4 = facets == null ? void 0 : (_facets$find4 = facets.find(facet => facet.key === 'channel')) == null ? void 0 : _facets$find4.value) != null ? _facets$find$value4 : null;
1300
1298
  };
1301
1299
 
1302
1300
  const SORT_MAP = {
@@ -1310,6 +1308,42 @@ const SORT_MAP = {
1310
1308
  score_desc: ''
1311
1309
  };
1312
1310
 
1311
+ /**
1312
+ * More info at: https://en.wikipedia.org/wiki/Order_statistic
1313
+ */
1314
+ // O(n) search to find the max of an array
1315
+ const min = (array, cmp) => {
1316
+ let best = 0;
1317
+
1318
+ for (let curr = 1; curr < array.length; curr++) {
1319
+ if (cmp(array[best], array[curr]) > 0) {
1320
+ best = curr;
1321
+ }
1322
+ }
1323
+
1324
+ return array[best];
1325
+ };
1326
+
1327
+ /**
1328
+ * This function implements Portal heuristics for returning the best sku for a product.
1329
+ *
1330
+ * The best sku is the one with the best (cheapest available) offer
1331
+ * */
1332
+
1333
+ const pickBestSku = skus => {
1334
+ const offersBySku = skus.flatMap(sku => sku.sellers.map(seller => ({
1335
+ offer: seller.commertialOffer,
1336
+ sku
1337
+ })));
1338
+ const best = min(offersBySku, ({
1339
+ offer: o1
1340
+ }, {
1341
+ offer: o2
1342
+ }) => bestOfferFirst(o1, o2));
1343
+ return best.sku;
1344
+ };
1345
+ const isValidSkuId = skuId => skuId !== '' && !Number.isNaN(Number(skuId));
1346
+
1313
1347
  const Query = {
1314
1348
  product: async (_, {
1315
1349
  locator
@@ -1317,6 +1351,8 @@ const Query = {
1317
1351
  // Insert channel in context for later usage
1318
1352
  const channel = findChannel(locator);
1319
1353
  const locale = findLocale(locator);
1354
+ const id = findSkuId(locator);
1355
+ const slug = findSlug(locator);
1320
1356
 
1321
1357
  if (channel) {
1322
1358
  mutateChannelContext(ctx, channel);
@@ -1329,9 +1365,50 @@ const Query = {
1329
1365
  const {
1330
1366
  loaders: {
1331
1367
  skuLoader
1368
+ },
1369
+ clients: {
1370
+ commerce,
1371
+ search
1332
1372
  }
1333
1373
  } = ctx;
1334
- return skuLoader.load(locator);
1374
+
1375
+ try {
1376
+ var _ref;
1377
+
1378
+ const skuId = (_ref = id != null ? id : slug == null ? void 0 : slug.split('-').pop()) != null ? _ref : '';
1379
+
1380
+ if (!isValidSkuId(skuId)) {
1381
+ throw new Error('Invalid SkuId');
1382
+ }
1383
+
1384
+ const sku = await skuLoader.load(skuId);
1385
+ return sku;
1386
+ } catch (err) {
1387
+ if (slug == null) {
1388
+ throw new BadRequestError('Missing slug or id');
1389
+ }
1390
+
1391
+ const route = await commerce.catalog.portal.pagetype(`${slug}/p`);
1392
+
1393
+ if (route.pageType !== 'Product' || !route.id) {
1394
+ throw new NotFoundError(`No product found for slug ${slug}`);
1395
+ }
1396
+
1397
+ const {
1398
+ products: [product]
1399
+ } = await search.products({
1400
+ page: 0,
1401
+ count: 1,
1402
+ query: `product:${route.id}`
1403
+ });
1404
+
1405
+ if (!product) {
1406
+ throw new NotFoundError(`No product found for id ${route.id}`);
1407
+ }
1408
+
1409
+ const sku = pickBestSku(product.items);
1410
+ return enhanceSku(sku, product);
1411
+ }
1335
1412
  },
1336
1413
  collection: (_, {
1337
1414
  slug
@@ -1576,8 +1653,10 @@ const StoreSeo = {
1576
1653
  description: ({
1577
1654
  description
1578
1655
  }) => description != null ? description : '',
1579
- titleTemplate: () => '',
1580
- canonical: () => ''
1656
+ canonical: ({
1657
+ canonical
1658
+ }) => canonical != null ? canonical : '',
1659
+ titleTemplate: () => ''
1581
1660
  };
1582
1661
 
1583
1662
  const ObjectOrString = /*#__PURE__*/new GraphQLScalarType({