@scayle/storefront-core 7.64.3 → 7.65.0

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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @scayle/storefront-core
2
2
 
3
+ ## 7.65.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Improves the handling of `getOrderDataByCbd` RPC to return descriptive errors in case the validation of the token fails.
8
+
9
+ In case the token can't be validated using the Checkout Secret, this is now returned and a warning on the server is logged.
10
+
11
+ If the token has expired, this is now also returned and logged on the server.
12
+
13
+ - Support passing `categoryId` as an alternative to the category path in `getProductsByCategory` and `getFilters`
14
+
15
+ ### Patch Changes
16
+
17
+ - Fixed cached fallback ttl to be used only if passed `option.ttl` is undefined
18
+
19
+ ## 7.64.4
20
+
21
+ ### Patch Changes
22
+
23
+ - Replaced `radash` utils with custom native implementations
24
+
3
25
  ## 7.64.3
4
26
 
5
27
  ### Patch Changes
@@ -15,14 +15,10 @@ class CustomerAPIClient {
15
15
  this.context = context;
16
16
  }
17
17
  get headers() {
18
- const accessHeader = this.context.checkout.accessHeader;
19
18
  return {
20
19
  Authorization: `Bearer ${this.context.accessToken}`,
21
20
  Accept: "application/json",
22
- "Content-Type": "application/json",
23
- ...(accessHeader ? {
24
- "X-Access-Header": accessHeader
25
- } : {})
21
+ "Content-Type": "application/json"
26
22
  };
27
23
  }
28
24
  async sendRequest(request, retry = true) {
@@ -9,12 +9,10 @@ export class CustomerAPIClient {
9
9
  this.context = context;
10
10
  }
11
11
  get headers() {
12
- const accessHeader = this.context.checkout.accessHeader;
13
12
  return {
14
13
  Authorization: `Bearer ${this.context.accessToken}`,
15
14
  Accept: "application/json",
16
- "Content-Type": "application/json",
17
- ...accessHeader ? { "X-Access-Header": accessHeader } : {}
15
+ "Content-Type": "application/json"
18
16
  };
19
17
  }
20
18
  async sendRequest(request, retry = true) {
@@ -71,7 +71,7 @@ class Cached {
71
71
  if (!this.isCacheEnabled) {
72
72
  return;
73
73
  }
74
- const ttl = options?.ttl || 60 * MINUTE;
74
+ const ttl = options?.ttl ?? 60 * MINUTE;
75
75
  if (ttl) {
76
76
  await (0, _utils.timeout)(_constants.CACHE_TIMEOUT, this.cache.set(cacheKey, value, ttl));
77
77
  }
@@ -68,7 +68,7 @@ export class Cached {
68
68
  if (!this.isCacheEnabled) {
69
69
  return;
70
70
  }
71
- const ttl = options?.ttl || 60 * MINUTE;
71
+ const ttl = options?.ttl ?? 60 * MINUTE;
72
72
  if (ttl) {
73
73
  await timeout(CACHE_TIMEOUT, this.cache.set(cacheKey, value, ttl));
74
74
  }
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.transformToWhereCondition = exports.transformStateToFilters = exports.transformSortToFilter = exports.transformMinAndMaxPriceToFilter = exports.serializeFilters = exports.mergeFilters = exports.isFilterActive = exports.groupFiltersByKey = exports.groupFilterableValuesByKey = exports.getGroupedFilterableValues = exports.getFilterablePriceValue = exports.getActiveFilters = exports.deserializeFilters = void 0;
7
7
  var _storefrontApi = require("@scayle/storefront-api");
8
- var _radash = require("radash");
9
8
  var _sortingHelper = require("./sortingHelper.cjs");
10
9
  const transformToWhereCondition = conditions => {
11
10
  const where = {
@@ -108,7 +107,13 @@ const getActiveFilters = (filters, activeFilters) => {
108
107
  };
109
108
  exports.getActiveFilters = getActiveFilters;
110
109
  const groupFiltersByKey = filters => {
111
- return Object.entries((0, _radash.group)(filters, it => it.key));
110
+ const groupedFilters = filters.reduce((acc, item) => {
111
+ const groupId = item.key;
112
+ if (!acc[groupId]) acc[groupId] = [];
113
+ acc[groupId].push(item);
114
+ return acc;
115
+ }, {});
116
+ return Object.entries(groupedFilters);
112
117
  };
113
118
  exports.groupFiltersByKey = groupFiltersByKey;
114
119
  const transformMinAndMaxPriceToFilter = prices => {
@@ -145,7 +150,7 @@ const getFilterablePriceValue = (filterableValues, key = "min") => {
145
150
  };
146
151
  exports.getFilterablePriceValue = getFilterablePriceValue;
147
152
  const serializeFilters = filter => {
148
- if ((0, _radash.isEmpty)(filter)) {
153
+ if (Object.keys(filter).length === 0) {
149
154
  return void 0;
150
155
  }
151
156
  return Object.assign({}, ...Object.entries(filter).map(([filterName, filterValue]) => {
@@ -33,7 +33,7 @@ export declare const transformStateToFilters: (state: {
33
33
  export declare const mergeFilters: (filters: TransformedFilter[]) => Record<string, any>;
34
34
  export declare const isFilterActive: (filters: Record<string, any>, filterToCheck: TransformedFilter) => any;
35
35
  export declare const getActiveFilters: (filters: Record<string, any>, activeFilters: Record<string, any>) => TransformedFilter[];
36
- export declare const groupFiltersByKey: (filters: TransformedFilter[]) => any[];
36
+ export declare const groupFiltersByKey: (filters: TransformedFilter[]) => [string, TransformedFilter[]][];
37
37
  export declare const transformMinAndMaxPriceToFilter: (prices: (CentAmount | undefined)[]) => any;
38
38
  export declare const transformSortToFilter: (sort: string) => {
39
39
  by: import("@scayle/storefront-api").APISortOption;
@@ -1,5 +1,4 @@
1
1
  import { FilterTypes } from "@scayle/storefront-api";
2
- import { group, isEmpty } from "radash";
3
2
  import { getSortByValue } from "./sortingHelper.mjs";
4
3
  export const transformToWhereCondition = (conditions) => {
5
4
  const where = { attributes: [] };
@@ -96,7 +95,13 @@ export const getActiveFilters = (filters, activeFilters) => {
96
95
  return [].concat(...Object.values(filters)).filter((item) => isFilterActive(activeFilters, item)) || [];
97
96
  };
98
97
  export const groupFiltersByKey = (filters) => {
99
- return Object.entries(group(filters, (it) => it.key));
98
+ const groupedFilters = filters.reduce((acc, item) => {
99
+ const groupId = item.key;
100
+ if (!acc[groupId]) acc[groupId] = [];
101
+ acc[groupId].push(item);
102
+ return acc;
103
+ }, {});
104
+ return Object.entries(groupedFilters);
100
105
  };
101
106
  export const transformMinAndMaxPriceToFilter = (prices) => {
102
107
  const [min = 0, max = 1e5] = prices;
@@ -127,7 +132,7 @@ export const getFilterablePriceValue = (filterableValues, key = "min") => {
127
132
  return prices.value[key];
128
133
  };
129
134
  export const serializeFilters = (filter) => {
130
- if (isEmpty(filter)) {
135
+ if (Object.keys(filter).length === 0) {
131
136
  return void 0;
132
137
  }
133
138
  return Object.assign(
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.slugify = exports.isVariantInStock = exports.isInStock = exports.getVariantCrosssellingValues = exports.getVariantBySize = exports.getVariant = exports.getTotalAppliedReductions = exports.getSizeFromVariant = exports.getSizeFromSpecificVariant = exports.getProductSiblings = exports.getProductPath = exports.getProductColors = exports.getProductAndSiblingsColors = exports.getPrice = exports.getOriginalPrice = exports.getLowestPrice = exports.getLatestCategory = exports.getCategoriesByRoute = exports.getBadgeLabel = exports.getAttribute = exports.getAppliedReductionsByCategory = exports.getAllSizesFromVariants = void 0;
7
7
  var _storefrontApi = require("@scayle/storefront-api");
8
- var _radash = require("radash");
9
8
  var _slugify = _interopRequireDefault(require("slugify"));
10
9
  var _product = require("../constants/product.cjs");
11
10
  var _attributeHelpers = require("./attributeHelpers.cjs");
@@ -97,7 +96,10 @@ const getVariant = (variants, id) => {
97
96
  return variants?.find(variant => variant.id === id);
98
97
  };
99
98
  exports.getVariant = getVariant;
100
- const getAllSizesFromVariants = (variantsAttributes, attributeName = "shopSize") => (0, _radash.unique)(variantsAttributes.map(variant => (0, _storefrontApi.getFirstAttributeValue)(variant.attributes, attributeName)).filter(Boolean), it => it?.id);
99
+ const getAllSizesFromVariants = (variantsAttributes, attributeName = "shopSize") => {
100
+ const array = variantsAttributes.map(variant => (0, _storefrontApi.getFirstAttributeValue)(variant.attributes, attributeName)).filter(Boolean);
101
+ return [...new Map(array.map(item => [item?.id ?? item, item])).values()];
102
+ };
101
103
  exports.getAllSizesFromVariants = getAllSizesFromVariants;
102
104
  const getProductSiblings = (product, colorAttributeName = "colorDetail") => {
103
105
  if (!product) {
@@ -180,7 +182,7 @@ const getVariantCrosssellingValues = variants => {
180
182
  return [];
181
183
  }
182
184
  const crossellings = variants.map(variant => variant.advancedAttributes?.variantCrosssellings).filter(Boolean);
183
- const uniqueCrossellings = (0, _radash.unique)(crossellings, it => it?.id);
185
+ const uniqueCrossellings = [...new Map(crossellings.map(item => [item?.id ?? item, item])).values()];
184
186
  const values = uniqueCrossellings.map(r => r?.values);
185
187
  const fieldSets = (0, _arrayHelpers.flattenDeep)(values).map(r => r?.fieldSet);
186
188
  return (0, _arrayHelpers.flattenDeep)(fieldSets).map(r => r?.value).filter(it => !!it);
@@ -30,7 +30,7 @@ export declare const getAppliedReductionsByCategory: (price: VariantPrice | Bask
30
30
  export declare const getSizeFromVariant: (variant: Variant, attributeName?: string) => Value | undefined;
31
31
  export declare const getSizeFromSpecificVariant: (product: Product, variantId?: number) => Value | null | undefined;
32
32
  export declare const getVariant: (variants: Variant[], id: number) => Variant | undefined;
33
- export declare const getAllSizesFromVariants: (variantsAttributes: Variant[], attributeName?: string) => (Value | undefined)[];
33
+ export declare const getAllSizesFromVariants: (variantsAttributes: Variant[], attributeName?: string) => any[];
34
34
  export declare const getProductSiblings: (product?: Product | null, colorAttributeName?: string) => ProductSibling[];
35
35
  export declare const getProductColors: (product: Product, colorAttributeName?: string) => string[];
36
36
  export declare const getVariantBySize: (variants: Variant[], size: Value, sizeAttributeName?: string) => Variant | undefined;
@@ -1,5 +1,4 @@
1
1
  import { getFirstAttributeValue } from "@scayle/storefront-api";
2
- import { unique } from "radash";
3
2
  import baseSlugify from "slugify";
4
3
  import { ProductImageType } from "../constants/product.mjs";
5
4
  import { getAttributeValue, getAttributeValueTuples } from "./attributeHelpers.mjs";
@@ -73,12 +72,12 @@ export const getSizeFromSpecificVariant = (product, variantId) => {
73
72
  export const getVariant = (variants, id) => {
74
73
  return variants?.find((variant) => variant.id === id);
75
74
  };
76
- export const getAllSizesFromVariants = (variantsAttributes, attributeName = "shopSize") => unique(
77
- variantsAttributes.map(
75
+ export const getAllSizesFromVariants = (variantsAttributes, attributeName = "shopSize") => {
76
+ const array = variantsAttributes.map(
78
77
  (variant) => getFirstAttributeValue(variant.attributes, attributeName)
79
- ).filter(Boolean),
80
- (it) => it?.id
81
- );
78
+ ).filter(Boolean);
79
+ return [...new Map(array.map((item) => [item?.id ?? item, item])).values()];
80
+ };
82
81
  export const getProductSiblings = (product, colorAttributeName = "colorDetail") => {
83
82
  if (!product) {
84
83
  return [];
@@ -163,7 +162,9 @@ export const getVariantCrosssellingValues = (variants) => {
163
162
  return [];
164
163
  }
165
164
  const crossellings = variants.map((variant) => variant.advancedAttributes?.variantCrosssellings).filter(Boolean);
166
- const uniqueCrossellings = unique(crossellings, (it) => it?.id);
165
+ const uniqueCrossellings = [
166
+ ...new Map(crossellings.map((item) => [item?.id ?? item, item])).values()
167
+ ];
167
168
  const values = uniqueCrossellings.map((r) => r?.values);
168
169
  const fieldSets = flattenDeep(values).map((r) => r?.fieldSet);
169
170
  return flattenDeep(fieldSets).map((r) => r?.value).filter((it) => !!it);
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.stripShopLocaleFromPath = exports.purifySensitiveValue = exports.purifySensitiveData = exports.createAndPurifyHeaders = void 0;
7
- var _radash = require("radash");
8
7
  const SANITIZATION_MASK = "********";
9
8
  const regex = /(?<!^).(?!$)/g;
10
9
  const stripShopLocaleFromPath = (locale, path, splitter = "/") => path.split(splitter).filter(segment => segment.toLowerCase() !== locale.toLowerCase()).join("/");
@@ -15,7 +14,7 @@ const purifySensitiveValue = (value, showFirstAndLastChar = false) => {
15
14
  exports.purifySensitiveValue = purifySensitiveValue;
16
15
  const purifySensitiveData = (data = {}, blacklistedKeys = ["password"], showFirstAndLastChar = false) => {
17
16
  return Object.entries(data).reduce((purifiedPayload, [key, value]) => {
18
- if ((0, _radash.isObject)(value)) {
17
+ if (!!value && value.constructor === Object) {
19
18
  purifiedPayload[key] = purifySensitiveData(value, blacklistedKeys);
20
19
  return purifiedPayload;
21
20
  }
@@ -30,7 +29,7 @@ const purifySensitiveData = (data = {}, blacklistedKeys = ["password"], showFirs
30
29
  };
31
30
  exports.purifySensitiveData = purifySensitiveData;
32
31
  const createAndPurifyHeaders = headers => {
33
- const sanitizedHeaders = (0, _radash.shake)(headers);
32
+ const sanitizedHeaders = Object.fromEntries(Object.entries(headers).filter(([_, value]) => value !== void 0));
34
33
  return new Headers(sanitizedHeaders);
35
34
  };
36
35
  exports.createAndPurifyHeaders = createAndPurifyHeaders;
@@ -1,4 +1,3 @@
1
- import { isObject, shake } from "radash";
2
1
  const SANITIZATION_MASK = "********";
3
2
  const regex = /(?<!^).(?!$)/g;
4
3
  export const stripShopLocaleFromPath = (locale, path, splitter = "/") => path.split(splitter).filter((segment) => segment.toLowerCase() !== locale.toLowerCase()).join("/");
@@ -8,7 +7,7 @@ export const purifySensitiveValue = (value, showFirstAndLastChar = false) => {
8
7
  export const purifySensitiveData = (data = {}, blacklistedKeys = ["password"], showFirstAndLastChar = false) => {
9
8
  return Object.entries(data).reduce(
10
9
  (purifiedPayload, [key, value]) => {
11
- if (isObject(value)) {
10
+ if (!!value && value.constructor === Object) {
12
11
  purifiedPayload[key] = purifySensitiveData(value, blacklistedKeys);
13
12
  return purifiedPayload;
14
13
  }
@@ -26,6 +25,8 @@ export const purifySensitiveData = (data = {}, blacklistedKeys = ["password"], s
26
25
  );
27
26
  };
28
27
  export const createAndPurifyHeaders = (headers) => {
29
- const sanitizedHeaders = shake(headers);
28
+ const sanitizedHeaders = Object.fromEntries(
29
+ Object.entries(headers).filter(([_, value]) => value !== void 0)
30
+ );
30
31
  return new Headers(sanitizedHeaders);
31
32
  };
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.getSortingValues = exports.getSortByValue = void 0;
7
7
  var _storefrontApi = require("@scayle/storefront-api");
8
- var _radash = require("radash");
9
8
  var _sorting = require("../constants/sorting.cjs");
10
9
  const SORTING_VALUES = {
11
10
  topSeller: {
@@ -44,7 +43,9 @@ const SORTING_VALUES = {
44
43
  query: _sorting.SortQuery.REDUCTION_ASC
45
44
  }
46
45
  };
47
- const getSortingValues = (options = ["topSeller", "dateNewest", "priceDesc", "priceAsc", "reductionDesc", "reductionAsc"]) => (0, _radash.pick)(SORTING_VALUES, options);
46
+ const getSortingValues = (options = ["topSeller", "dateNewest", "priceDesc", "priceAsc", "reductionDesc", "reductionAsc"]) => {
47
+ return Object.fromEntries(options.filter(key => key in SORTING_VALUES).map(key => [key, SORTING_VALUES[key]]));
48
+ };
48
49
  exports.getSortingValues = getSortingValues;
49
50
  const getSortByValue = (query, defaultSort) => {
50
51
  switch (query) {
@@ -1,42 +1,37 @@
1
1
  import { APISortOption, APISortOrder } from '@scayle/storefront-api';
2
2
  import type { Query, SortingValueKey } from '../index';
3
- export declare const getSortingValues: (options?: Array<SortingValueKey>) => Pick<{
4
- topSeller: {
3
+ export declare const getSortingValues: (options?: Array<SortingValueKey>) => {
4
+ [k: string]: {
5
5
  by: APISortOption;
6
6
  direction: APISortOrder;
7
7
  name: "topseller";
8
8
  query: "topseller";
9
- };
10
- dateNewest: {
9
+ } | {
11
10
  by: APISortOption;
12
11
  name: "date_newest";
13
12
  query: "date-newest";
14
- };
15
- priceDesc: {
13
+ } | {
16
14
  by: APISortOption;
17
15
  direction: APISortOrder;
18
16
  name: "price_desc";
19
17
  query: "price-desc";
20
- };
21
- priceAsc: {
18
+ } | {
22
19
  by: APISortOption;
23
20
  direction: APISortOrder;
24
21
  name: "price_asc";
25
22
  query: "price-asc";
26
- };
27
- reductionDesc: {
23
+ } | {
28
24
  by: APISortOption;
29
25
  direction: APISortOrder;
30
26
  name: "reduction_desc";
31
27
  query: "reduction-desc";
32
- };
33
- reductionAsc: {
28
+ } | {
34
29
  by: APISortOption;
35
30
  direction: APISortOrder;
36
31
  name: "reduction_asc";
37
32
  query: "reduction-asc";
38
33
  };
39
- }, SortingValueKey>;
34
+ };
40
35
  export declare const getSortByValue: (query: Query, defaultSort?: SortingValueKey) => {
41
36
  by: APISortOption;
42
37
  direction: APISortOrder;
@@ -1,5 +1,4 @@
1
1
  import { APISortOption, APISortOrder } from "@scayle/storefront-api";
2
- import { pick } from "radash";
3
2
  import { SortName, SortQuery } from "../constants/sorting.mjs";
4
3
  const SORTING_VALUES = {
5
4
  topSeller: {
@@ -45,7 +44,13 @@ export const getSortingValues = (options = [
45
44
  "priceAsc",
46
45
  "reductionDesc",
47
46
  "reductionAsc"
48
- ]) => pick(SORTING_VALUES, options);
47
+ ]) => {
48
+ return Object.fromEntries(
49
+ options.filter((key) => key in SORTING_VALUES).map(
50
+ (key) => [key, SORTING_VALUES[key]]
51
+ )
52
+ );
53
+ };
49
54
  export const getSortByValue = (query, defaultSort) => {
50
55
  switch (query) {
51
56
  case SortQuery.PRICE_DESC:
@@ -4,37 +4,35 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getOrderDataByCbd = void 0;
7
+ var _constants = require("../../constants/index.cjs");
8
+ var _errors = require("../../errors/index.cjs");
7
9
  var _hash = require("../../utils/hash.cjs");
8
10
  const getOrderDataByCbd = exports.getOrderDataByCbd = async function getOrderDataByCbd2({
9
11
  cbdToken
10
12
  }, context) {
11
- if (!cbdToken) {
12
- return;
13
+ const payload = await (0, _hash.verifyOrderSuccessToken)(cbdToken, context.checkout.secret);
14
+ if (!payload) {
15
+ context.log.warn("Unable to verify CBD token. Please check that you configured the correct Checkout Secret");
16
+ return new _errors.ErrorResponse(_constants.HttpStatusCode.BAD_REQUEST, _constants.HttpStatusMessage.BAD_REQUEST, "Unable to verify CBD token.");
13
17
  }
14
- const shopId = context.shopId;
15
- const accessHeader = context.checkout.accessHeader;
16
- const checkoutSecret = context.checkout.secret;
17
- const decodedPayload = await (0, _hash.verifyToken)(cbdToken, checkoutSecret);
18
- if (decodedPayload) {
19
- const payload = JSON.parse(decodedPayload);
20
- const checkoutUsername = context.checkout.user;
21
- const checkoutToken = context.checkout.token;
22
- const checkoutUrl = context.checkout.url;
23
- if (context.checkout.cbdExpiration && Math.floor(Date.now() / 1e3) - payload.issued_at > context.checkout.cbdExpiration) {
24
- context.log.debug("Attempting to use expired CBD token");
25
- return;
18
+ if (context.checkout.cbdExpiration && Math.floor(Date.now() / 1e3) - payload.issued_at > context.checkout.cbdExpiration) {
19
+ context.log.warn("Attempting to use expired CBD token");
20
+ return new _errors.ErrorResponse(_constants.HttpStatusCode.BAD_REQUEST, _constants.HttpStatusMessage.BAD_REQUEST, "The CBD token has expired.");
21
+ }
22
+ const checkoutUrl = context.checkout.url;
23
+ const basicAuth = (0, _hash.encodeBase64)(`${context.checkout.user}:${context.checkout.token}`);
24
+ const response = await fetch(`${checkoutUrl}/api/v1/orders/${payload.order_id}`, {
25
+ headers: {
26
+ Accept: "application/json",
27
+ Authorization: `Basic ${basicAuth}`,
28
+ "X-Shop-Id": context.shopId.toString()
26
29
  }
27
- const accessToken = (0, _hash.encodeBase64)(`${checkoutUsername}:${unescape(checkoutToken)}`);
28
- const response = await fetch(`${checkoutUrl}/api/v1/orders/${payload.order_id}`, {
29
- headers: {
30
- Accept: "application/json",
31
- Authorization: `Basic ${accessToken}`,
32
- "x-shop-id": shopId.toString(),
33
- ...(accessHeader ? {
34
- "X-Access-Header": accessHeader
35
- } : {})
36
- }
37
- });
30
+ });
31
+ if (response.ok) {
38
32
  return await response.json();
39
33
  }
34
+ context.log.error(`Unexpected status code when fetching order from Checkout API: ${response.status}`);
35
+ return new _errors.ErrorResponse(_constants.HttpStatusCode.INTERNAL_SERVER_ERROR, _constants.HttpStatusMessage.INTERNAL_SERVER_ERROR, "Unknown error", {
36
+ detail: `Fetching order failed with status code ${response.status}`
37
+ });
40
38
  };
@@ -1,4 +1,5 @@
1
+ import { ErrorResponse } from '../../errors';
1
2
  import type { Order, RpcContext } from '../../types';
2
3
  export declare const getOrderDataByCbd: ({ cbdToken }: {
3
4
  cbdToken: string;
4
- }, context: RpcContext) => Promise<Order | undefined>;
5
+ }, context: RpcContext) => Promise<Order | ErrorResponse>;
@@ -1,35 +1,55 @@
1
- import { encodeBase64, verifyToken } from "../../utils/hash.mjs";
1
+ import { HttpStatusCode, HttpStatusMessage } from "../../constants/index.mjs";
2
+ import { ErrorResponse } from "../../errors/index.mjs";
3
+ import { encodeBase64, verifyOrderSuccessToken } from "../../utils/hash.mjs";
2
4
  export const getOrderDataByCbd = async function getOrderDataByCbd2({ cbdToken }, context) {
3
- if (!cbdToken) {
4
- return;
5
+ const payload = await verifyOrderSuccessToken(
6
+ cbdToken,
7
+ context.checkout.secret
8
+ );
9
+ if (!payload) {
10
+ context.log.warn(
11
+ "Unable to verify CBD token. Please check that you configured the correct Checkout Secret"
12
+ );
13
+ return new ErrorResponse(
14
+ HttpStatusCode.BAD_REQUEST,
15
+ HttpStatusMessage.BAD_REQUEST,
16
+ "Unable to verify CBD token."
17
+ );
5
18
  }
6
- const shopId = context.shopId;
7
- const accessHeader = context.checkout.accessHeader;
8
- const checkoutSecret = context.checkout.secret;
9
- const decodedPayload = await verifyToken(cbdToken, checkoutSecret);
10
- if (decodedPayload) {
11
- const payload = JSON.parse(decodedPayload);
12
- const checkoutUsername = context.checkout.user;
13
- const checkoutToken = context.checkout.token;
14
- const checkoutUrl = context.checkout.url;
15
- if (context.checkout.cbdExpiration && Math.floor(Date.now() / 1e3) - payload.issued_at > context.checkout.cbdExpiration) {
16
- context.log.debug("Attempting to use expired CBD token");
17
- return;
18
- }
19
- const accessToken = encodeBase64(
20
- `${checkoutUsername}:${unescape(checkoutToken)}`
19
+ if (context.checkout.cbdExpiration && Math.floor(Date.now() / 1e3) - payload.issued_at > context.checkout.cbdExpiration) {
20
+ context.log.warn("Attempting to use expired CBD token");
21
+ return new ErrorResponse(
22
+ HttpStatusCode.BAD_REQUEST,
23
+ HttpStatusMessage.BAD_REQUEST,
24
+ "The CBD token has expired."
21
25
  );
22
- const response = await fetch(
23
- `${checkoutUrl}/api/v1/orders/${payload.order_id}`,
24
- {
25
- headers: {
26
- Accept: "application/json",
27
- Authorization: `Basic ${accessToken}`,
28
- "x-shop-id": shopId.toString(),
29
- ...accessHeader ? { "X-Access-Header": accessHeader } : {}
30
- }
26
+ }
27
+ const checkoutUrl = context.checkout.url;
28
+ const basicAuth = encodeBase64(
29
+ `${context.checkout.user}:${context.checkout.token}`
30
+ );
31
+ const response = await fetch(
32
+ `${checkoutUrl}/api/v1/orders/${payload.order_id}`,
33
+ {
34
+ headers: {
35
+ Accept: "application/json",
36
+ Authorization: `Basic ${basicAuth}`,
37
+ "X-Shop-Id": context.shopId.toString()
31
38
  }
32
- );
39
+ }
40
+ );
41
+ if (response.ok) {
33
42
  return await response.json();
34
43
  }
44
+ context.log.error(
45
+ `Unexpected status code when fetching order from Checkout API: ${response.status}`
46
+ );
47
+ return new ErrorResponse(
48
+ HttpStatusCode.INTERNAL_SERVER_ERROR,
49
+ HttpStatusMessage.INTERNAL_SERVER_ERROR,
50
+ "Unknown error",
51
+ {
52
+ detail: `Fetching order failed with status code ${response.status}`
53
+ }
54
+ );
35
55
  };
@@ -5,10 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.getCheckoutToken = void 0;
7
7
  var _jose = require("jose");
8
+ var _types = require("../../../types/index.cjs");
8
9
  var _errors = require("../../../errors/index.cjs");
9
10
  var _constants = require("../../../constants/index.cjs");
10
11
  var _user = require("../user.cjs");
11
12
  const getCheckoutToken = exports.getCheckoutToken = async function getCheckoutToken2(jwtPayload = {}, context) {
13
+ if (!(0, _types.hasSession)(context)) {
14
+ return new _errors.ErrorResponse(_constants.HttpStatusCode.BAD_REQUEST, _constants.HttpStatusMessage.BAD_REQUEST, "No Session found");
15
+ }
12
16
  if (!context.accessToken) {
13
17
  return new _errors.ErrorResponse(_constants.HttpStatusCode.UNAUTHORIZED, _constants.HttpStatusMessage.UNAUTHORIZED, "No access token present");
14
18
  }
@@ -33,7 +37,7 @@ const getCheckoutToken = exports.getCheckoutToken = async function getCheckoutTo
33
37
  carrier,
34
38
  basketId: context.basketKey,
35
39
  campaignKey: context.campaignKey
36
- }).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"7.64.3"}`).setProtectedHeader({
40
+ }).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"7.65.0"}`).setProtectedHeader({
37
41
  alg: "HS256",
38
42
  typ: "JWT"
39
43
  }).sign(secret);
@@ -1,8 +1,16 @@
1
1
  import { SignJWT } from "jose";
2
+ import { hasSession } from "../../../types/index.mjs";
2
3
  import { ErrorResponse } from "../../../errors/index.mjs";
3
4
  import { HttpStatusCode, HttpStatusMessage } from "../../../constants/index.mjs";
4
5
  import { getAccessToken } from "../user.mjs";
5
6
  export const getCheckoutToken = async function getCheckoutToken2(jwtPayload = {}, context) {
7
+ if (!hasSession(context)) {
8
+ return new ErrorResponse(
9
+ HttpStatusCode.BAD_REQUEST,
10
+ HttpStatusMessage.BAD_REQUEST,
11
+ "No Session found"
12
+ );
13
+ }
6
14
  if (!context.accessToken) {
7
15
  return new ErrorResponse(
8
16
  HttpStatusCode.UNAUTHORIZED,
@@ -27,7 +35,7 @@ export const getCheckoutToken = async function getCheckoutToken2(jwtPayload = {}
27
35
  carrier,
28
36
  basketId: context.basketKey,
29
37
  campaignKey: context.campaignKey
30
- }).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"7.64.3"}`).setProtectedHeader({ alg: "HS256", typ: "JWT" }).sign(secret);
38
+ }).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"7.65.0"}`).setProtectedHeader({ alg: "HS256", typ: "JWT" }).sign(secret);
31
39
  return {
32
40
  accessToken: refreshedAccessToken,
33
41
  checkoutJwt
@@ -68,31 +68,36 @@ const getProductsByReferenceKeys = exports.getProductsByReferenceKeys = async fu
68
68
  pricePromotionKey: options.pricePromotionKey
69
69
  });
70
70
  };
71
- const getProductsCount = exports.getProductsCount = async function getProductsCount2({
72
- category = "/",
73
- categoryId = void 0,
74
- where = void 0,
75
- includeSoldOut = false,
76
- includeSellableForFree = false,
77
- orFiltersOperator = void 0
78
- }, {
71
+ const getProductsCount = exports.getProductsCount = async function getProductsCount2(params, {
79
72
  cached,
80
73
  bapiClient,
81
74
  campaignKey
82
75
  }) {
83
- let result;
84
- if (category !== "/") {
85
- const sanitizedPath = (0, _helpers.splitAndRemoveEmpty)(category);
86
- result = await cached(bapiClient.categories.getByPath, {
87
- cacheKeyPrefix: `getByPath-categories-${sanitizedPath}`
88
- })(sanitizedPath);
76
+ const {
77
+ where = void 0,
78
+ includeSoldOut = false,
79
+ includeSellableForFree = false,
80
+ orFiltersOperator = void 0
81
+ } = params;
82
+ let category;
83
+ let categoryId;
84
+ if ("category" in params && !params.category) {
85
+ category = "/";
86
+ }
87
+ if ("categoryId" in params) {
88
+ categoryId = params.categoryId;
89
+ } else if (category && category !== "/") {
90
+ const result = await cached(bapiClient.categories.getByPath, {
91
+ cacheKeyPrefix: `getByPath-categories-${category}`
92
+ })((0, _helpers.splitAndRemoveEmpty)(category));
93
+ categoryId = result.id;
89
94
  }
90
95
  const productCount = await cached(bapiClient.products.query, {
91
96
  ttl: 15 * _cache.MINUTE,
92
97
  cacheKeyPrefix: "products-query"
93
98
  })({
94
99
  where: {
95
- categoryId: categoryId ?? result?.id,
100
+ categoryId,
96
101
  minPrice: where?.minPrice,
97
102
  maxPrice: where?.maxPrice,
98
103
  attributes: where?.attributes,
@@ -131,32 +136,38 @@ const fetchAllFiltersForCategory = exports.fetchAllFiltersForCategory = async fu
131
136
  return await cached(fetchAndMapFiltersToSlugs, {
132
137
  ttl: 4 * 60 * 60,
133
138
  // cached for 4 hours
134
- cacheKey: `filters-for-category-${category.slug}`
139
+ cacheKey: `filters-for-category-${category.id}`
135
140
  })();
136
141
  };
137
- const getFilters = exports.getFilters = async function getFilters2({
138
- category = "/",
139
- includedFilters,
140
- where = void 0,
141
- includeSoldOut = false,
142
- includeSellableForFree = false,
143
- orFiltersOperator
144
- }, context) {
145
- let result;
142
+ const getFilters = exports.getFilters = async function getFilters2(params, context) {
143
+ const {
144
+ includedFilters,
145
+ where = void 0,
146
+ includeSoldOut = false,
147
+ includeSellableForFree = false,
148
+ orFiltersOperator
149
+ } = params;
150
+ let category;
151
+ let categoryId;
146
152
  const {
147
153
  cached,
148
154
  bapiClient,
149
155
  campaignKey
150
156
  } = context;
151
- if (category !== "/") {
152
- result = await cached(bapiClient.categories.getByPath, {
157
+ if ("category" in params && !params.category) {
158
+ category = "/";
159
+ }
160
+ if ("categoryId" in params) {
161
+ categoryId = params.categoryId;
162
+ } else if (category && category !== "/") {
163
+ const result = await cached(bapiClient.categories.getByPath, {
153
164
  cacheKeyPrefix: `getByPath-categories-${category}`
154
165
  })((0, _helpers.splitAndRemoveEmpty)(category));
166
+ categoryId = result.id;
155
167
  }
156
168
  const response = await fetchAllFiltersForCategory({
157
169
  category: {
158
- id: result?.id,
159
- slug: category
170
+ id: categoryId
160
171
  },
161
172
  includedFilters
162
173
  }, context);
@@ -173,7 +184,7 @@ const getFilters = exports.getFilters = async function getFilters2({
173
184
  cacheKeyPrefix: `get-filters-${category}`
174
185
  })({
175
186
  where: {
176
- categoryId: result?.id,
187
+ categoryId,
177
188
  minPrice: where?.minPrice,
178
189
  maxPrice: where?.maxPrice,
179
190
  term: where?.term,
@@ -189,7 +200,7 @@ const getFilters = exports.getFilters = async function getFilters2({
189
200
  cacheKeyPrefix: `products-query-category-${category === "/" ? "root" : category}`
190
201
  })({
191
202
  where: {
192
- categoryId: result?.id,
203
+ categoryId,
193
204
  minPrice: where?.minPrice,
194
205
  maxPrice: where?.maxPrice,
195
206
  term: where?.term,
@@ -207,34 +218,40 @@ const getFilters = exports.getFilters = async function getFilters2({
207
218
  unfilteredCount: productCount?.pagination.total
208
219
  };
209
220
  };
210
- const getProductsByCategory = exports.getProductsByCategory = async function getProductsByCategory2({
211
- category = "/",
212
- cache,
213
- with: _with,
214
- perPage = 20,
215
- page = 1,
216
- where = void 0,
217
- sort = void 0,
218
- pricePromotionKey = "",
219
- includeSellableForFree = void 0,
220
- includeSoldOut = void 0,
221
- orFiltersOperator = void 0
222
- }, context) {
223
- let result;
221
+ const getProductsByCategory = exports.getProductsByCategory = async function getProductsByCategory2(params, context) {
222
+ const {
223
+ cache,
224
+ with: _with,
225
+ perPage = 20,
226
+ page = 1,
227
+ where = void 0,
228
+ sort = void 0,
229
+ pricePromotionKey = "",
230
+ includeSellableForFree = void 0,
231
+ includeSoldOut = void 0,
232
+ orFiltersOperator = void 0
233
+ } = params;
224
234
  const {
225
235
  cached,
226
236
  bapiClient,
227
237
  campaignKey
228
238
  } = context;
229
- if (category !== "/") {
230
- result = await cached(bapiClient.categories.getByPath, {
239
+ let category;
240
+ let categoryId;
241
+ if ("category" in params && !params.category) {
242
+ category = "/";
243
+ }
244
+ if ("categoryId" in params) {
245
+ categoryId = params.categoryId;
246
+ } else if (category && category !== "/") {
247
+ const result = await cached(bapiClient.categories.getByPath, {
231
248
  cacheKeyPrefix: `getByPath-categories-${category}`
232
249
  })((0, _helpers.splitAndRemoveEmpty)(category));
250
+ categoryId = result.id;
233
251
  }
234
252
  const response = await fetchAllFiltersForCategory({
235
253
  category: {
236
- id: result?.id,
237
- slug: category
254
+ id: categoryId
238
255
  }
239
256
  }, context);
240
257
  if (response instanceof _errors.ErrorResponse) {
@@ -255,7 +272,7 @@ const getProductsByCategory = exports.getProductsByCategory = async function get
255
272
  })({
256
273
  where: {
257
274
  term: where?.term,
258
- categoryId: result?.id,
275
+ categoryId,
259
276
  minPrice: where?.minPrice,
260
277
  maxPrice: where?.maxPrice,
261
278
  attributes: [...sanitizedAttributes, ...(where?.whitelistAttributes || [])],
@@ -4,21 +4,20 @@ import { ErrorResponse } from '../../errors';
4
4
  export declare const getProductById: (options: FetchProductParams, { bapiClient, cached, campaignKey, withParams }: RpcContext) => Promise<Product>;
5
5
  export declare const getProductsByIds: (options: FetchProductsByIdsParams, { bapiClient, cached, campaignKey, withParams }: RpcContext) => Promise<Product[]>;
6
6
  export declare const getProductsByReferenceKeys: (options: FetchProductsByReferenceKeysParams, { bapiClient, cached, campaignKey, withParams }: RpcContext) => Promise<Product[]>;
7
- export declare const getProductsCount: ({ category, categoryId, where, includeSoldOut, includeSellableForFree, orFiltersOperator, }: FetchProductsCountParams, { cached, bapiClient, campaignKey }: RpcContext) => Promise<{
7
+ export declare const getProductsCount: (params: FetchProductsCountParams, { cached, bapiClient, campaignKey }: RpcContext) => Promise<{
8
8
  count: number;
9
9
  }>;
10
10
  export declare const fetchAllFiltersForCategory: ({ includedFilters, category }: {
11
11
  includedFilters?: string[];
12
12
  category: {
13
- slug: string;
14
13
  id?: number;
15
14
  };
16
15
  }, { cached, bapiClient, campaignKey }: RpcContext) => Promise<string[]>;
17
- export declare const getFilters: ({ category, includedFilters, where, includeSoldOut, includeSellableForFree, orFiltersOperator, }: FetchFiltersParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
16
+ export declare const getFilters: (params: FetchFiltersParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
18
17
  filters: FiltersEndpointResponseData;
19
18
  unfilteredCount: number;
20
19
  }>;
21
- export declare const getProductsByCategory: ({ category, cache, with: _with, perPage, page, where, sort, pricePromotionKey, includeSellableForFree, includeSoldOut, orFiltersOperator, }: FetchProductsByCategoryParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
20
+ export declare const getProductsByCategory: (params: FetchProductsByCategoryParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
22
21
  products: Product[];
23
22
  pagination: {
24
23
  current: number;
@@ -45,27 +45,32 @@ export const getProductsByReferenceKeys = async function getProductsByReferenceK
45
45
  pricePromotionKey: options.pricePromotionKey
46
46
  });
47
47
  };
48
- export const getProductsCount = async function getProductsCount2({
49
- category = "/",
50
- categoryId = void 0,
51
- where = void 0,
52
- includeSoldOut = false,
53
- includeSellableForFree = false,
54
- orFiltersOperator = void 0
55
- }, { cached, bapiClient, campaignKey }) {
56
- let result;
57
- if (category !== "/") {
58
- const sanitizedPath = splitAndRemoveEmpty(category);
59
- result = await cached(bapiClient.categories.getByPath, {
60
- cacheKeyPrefix: `getByPath-categories-${sanitizedPath}`
61
- })(sanitizedPath);
48
+ export const getProductsCount = async function getProductsCount2(params, { cached, bapiClient, campaignKey }) {
49
+ const {
50
+ where = void 0,
51
+ includeSoldOut = false,
52
+ includeSellableForFree = false,
53
+ orFiltersOperator = void 0
54
+ } = params;
55
+ let category;
56
+ let categoryId;
57
+ if ("category" in params && !params.category) {
58
+ category = "/";
59
+ }
60
+ if ("categoryId" in params) {
61
+ categoryId = params.categoryId;
62
+ } else if (category && category !== "/") {
63
+ const result = await cached(bapiClient.categories.getByPath, {
64
+ cacheKeyPrefix: `getByPath-categories-${category}`
65
+ })(splitAndRemoveEmpty(category));
66
+ categoryId = result.id;
62
67
  }
63
68
  const productCount = await cached(bapiClient.products.query, {
64
69
  ttl: 15 * MINUTE,
65
70
  cacheKeyPrefix: "products-query"
66
71
  })({
67
72
  where: {
68
- categoryId: categoryId ?? result?.id,
73
+ categoryId,
69
74
  minPrice: where?.minPrice,
70
75
  maxPrice: where?.maxPrice,
71
76
  attributes: where?.attributes,
@@ -95,26 +100,36 @@ export const fetchAllFiltersForCategory = async function fetchAllFiltersForCateg
95
100
  return await cached(fetchAndMapFiltersToSlugs, {
96
101
  ttl: 4 * 60 * 60,
97
102
  // cached for 4 hours
98
- cacheKey: `filters-for-category-${category.slug}`
103
+ cacheKey: `filters-for-category-${category.id}`
99
104
  })();
100
105
  };
101
- export const getFilters = async function getFilters2({
102
- category = "/",
103
- includedFilters,
104
- where = void 0,
105
- includeSoldOut = false,
106
- includeSellableForFree = false,
107
- orFiltersOperator
108
- }, context) {
109
- let result;
106
+ export const getFilters = async function getFilters2(params, context) {
107
+ const {
108
+ includedFilters,
109
+ where = void 0,
110
+ includeSoldOut = false,
111
+ includeSellableForFree = false,
112
+ orFiltersOperator
113
+ } = params;
114
+ let category;
115
+ let categoryId;
110
116
  const { cached, bapiClient, campaignKey } = context;
111
- if (category !== "/") {
112
- result = await cached(bapiClient.categories.getByPath, {
117
+ if ("category" in params && !params.category) {
118
+ category = "/";
119
+ }
120
+ if ("categoryId" in params) {
121
+ categoryId = params.categoryId;
122
+ } else if (category && category !== "/") {
123
+ const result = await cached(bapiClient.categories.getByPath, {
113
124
  cacheKeyPrefix: `getByPath-categories-${category}`
114
125
  })(splitAndRemoveEmpty(category));
126
+ categoryId = result.id;
115
127
  }
116
128
  const response = await fetchAllFiltersForCategory(
117
- { category: { id: result?.id, slug: category }, includedFilters },
129
+ {
130
+ category: { id: categoryId },
131
+ includedFilters
132
+ },
118
133
  context
119
134
  );
120
135
  if (response instanceof ErrorResponse) {
@@ -131,7 +146,7 @@ export const getFilters = async function getFilters2({
131
146
  cacheKeyPrefix: `get-filters-${category}`
132
147
  })({
133
148
  where: {
134
- categoryId: result?.id,
149
+ categoryId,
135
150
  minPrice: where?.minPrice,
136
151
  maxPrice: where?.maxPrice,
137
152
  term: where?.term,
@@ -151,7 +166,7 @@ export const getFilters = async function getFilters2({
151
166
  cacheKeyPrefix: `products-query-category-${category === "/" ? "root" : category}`
152
167
  })({
153
168
  where: {
154
- categoryId: result?.id,
169
+ categoryId,
155
170
  minPrice: where?.minPrice,
156
171
  maxPrice: where?.maxPrice,
157
172
  term: where?.term,
@@ -173,28 +188,39 @@ export const getFilters = async function getFilters2({
173
188
  unfilteredCount: productCount?.pagination.total
174
189
  };
175
190
  };
176
- export const getProductsByCategory = async function getProductsByCategory2({
177
- category = "/",
178
- cache,
179
- with: _with,
180
- perPage = 20,
181
- page = 1,
182
- where = void 0,
183
- sort = void 0,
184
- pricePromotionKey = "",
185
- includeSellableForFree = void 0,
186
- includeSoldOut = void 0,
187
- orFiltersOperator = void 0
188
- }, context) {
189
- let result;
191
+ export const getProductsByCategory = async function getProductsByCategory2(params, context) {
192
+ const {
193
+ cache,
194
+ with: _with,
195
+ perPage = 20,
196
+ page = 1,
197
+ where = void 0,
198
+ sort = void 0,
199
+ pricePromotionKey = "",
200
+ includeSellableForFree = void 0,
201
+ includeSoldOut = void 0,
202
+ orFiltersOperator = void 0
203
+ } = params;
190
204
  const { cached, bapiClient, campaignKey } = context;
191
- if (category !== "/") {
192
- result = await cached(bapiClient.categories.getByPath, {
205
+ let category;
206
+ let categoryId;
207
+ if ("category" in params && !params.category) {
208
+ category = "/";
209
+ }
210
+ if ("categoryId" in params) {
211
+ categoryId = params.categoryId;
212
+ } else if (category && category !== "/") {
213
+ const result = await cached(bapiClient.categories.getByPath, {
193
214
  cacheKeyPrefix: `getByPath-categories-${category}`
194
215
  })(splitAndRemoveEmpty(category));
216
+ categoryId = result.id;
195
217
  }
196
218
  const response = await fetchAllFiltersForCategory(
197
- { category: { id: result?.id, slug: category } },
219
+ {
220
+ category: {
221
+ id: categoryId
222
+ }
223
+ },
198
224
  context
199
225
  );
200
226
  if (response instanceof ErrorResponse) {
@@ -215,7 +241,7 @@ export const getProductsByCategory = async function getProductsByCategory2({
215
241
  )({
216
242
  where: {
217
243
  term: where?.term,
218
- categoryId: result?.id,
244
+ categoryId,
219
245
  minPrice: where?.minPrice,
220
246
  maxPrice: where?.maxPrice,
221
247
  attributes: [
@@ -15,8 +15,7 @@ export interface FilterParams {
15
15
  sort?: ProductSortConfig;
16
16
  orFiltersOperator?: ProductsSearchEndpointParameters['orFiltersOperator'];
17
17
  }
18
- export interface FetchFiltersParams {
19
- category: string;
18
+ export type FetchFiltersParams = {
20
19
  includedFilters?: Array<string>;
21
20
  where?: {
22
21
  term?: ProductSearchQuery['term'];
@@ -28,7 +27,13 @@ export interface FetchFiltersParams {
28
27
  includeSoldOut?: boolean;
29
28
  includeSellableForFree?: boolean;
30
29
  orFiltersOperator?: ProductsSearchEndpointParameters['orFiltersOperator'];
31
- }
30
+ } & ({
31
+ category?: string;
32
+ categoryId?: undefined;
33
+ } | {
34
+ categoryId: number;
35
+ category?: undefined;
36
+ });
32
37
  export interface FetchFiltersResponse {
33
38
  filters: FiltersEndpointResponseData;
34
39
  unfilteredCount: number;
@@ -43,8 +43,7 @@ export interface FetchProductsByReferenceKeysParams {
43
43
  with?: ProductWith;
44
44
  pricePromotionKey?: string;
45
45
  }
46
- export interface FetchProductsByCategoryParams {
47
- category: string;
46
+ export type FetchProductsByCategoryParams = {
48
47
  with?: ProductWith;
49
48
  cache?: CacheOptions;
50
49
  includedFilters?: Array<string>;
@@ -63,14 +62,18 @@ export interface FetchProductsByCategoryParams {
63
62
  includeSellableForFree?: boolean;
64
63
  includeSoldOut?: boolean;
65
64
  orFiltersOperator?: ProductsSearchEndpointParameters['orFiltersOperator'];
66
- }
65
+ } & ({
66
+ category?: string;
67
+ categoryId?: undefined;
68
+ } | {
69
+ categoryId: number;
70
+ category?: undefined;
71
+ });
67
72
  export interface FetchProductsByCategoryResponse {
68
73
  products: Product[];
69
74
  pagination: ProductsByIdsEndpointResponseData['pagination'];
70
75
  }
71
- export interface FetchProductsCountParams {
72
- category?: string;
73
- categoryId?: number;
76
+ export type FetchProductsCountParams = {
74
77
  where?: {
75
78
  term?: ProductSearchQuery['term'];
76
79
  minPrice?: ProductSearchQuery['minPrice'];
@@ -80,7 +83,13 @@ export interface FetchProductsCountParams {
80
83
  includeSoldOut?: boolean;
81
84
  includeSellableForFree?: boolean;
82
85
  orFiltersOperator?: ProductsSearchEndpointParameters['orFiltersOperator'];
83
- }
86
+ } & ({
87
+ category?: string;
88
+ categoryId?: undefined;
89
+ } | {
90
+ categoryId: number;
91
+ category?: undefined;
92
+ });
84
93
  export interface FetchProductsCountResponse {
85
94
  count: number;
86
95
  }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.verifyToken = exports.sha256 = exports.md5 = exports.hmac = exports.encodeBase64 = exports.decodeBase64 = exports.buildSignature = exports.buildHashPayload = void 0;
6
+ exports.verifyOrderSuccessToken = exports.sha256 = exports.md5 = exports.hmac = exports.encodeBase64 = exports.decodeBase64 = exports.buildSignature = exports.buildHashPayload = void 0;
7
7
  var _uncrypto = require("uncrypto");
8
8
  const md5 = async value => {
9
9
  if (!process.env.SFC_OMIT_MD5) {
@@ -54,14 +54,15 @@ const decodeBase64 = string => {
54
54
  return new TextDecoder().decode(base64ToBytes(string));
55
55
  };
56
56
  exports.decodeBase64 = decodeBase64;
57
- const verifyToken = async (token, secret) => {
57
+ const verifyOrderSuccessToken = async (token, secret) => {
58
58
  const [encodedPayload, signature] = token.split(".", 2);
59
59
  const expectedSignature = encodeBase64(await hmac(encodedPayload, secret));
60
60
  if (expectedSignature === signature) {
61
- return decodeBase64(encodedPayload);
61
+ return JSON.parse(decodeBase64(encodedPayload));
62
62
  }
63
+ return void 0;
63
64
  };
64
- exports.verifyToken = verifyToken;
65
+ exports.verifyOrderSuccessToken = verifyOrderSuccessToken;
65
66
  const buildHashPayload = payload => encodeBase64(JSON.stringify(payload));
66
67
  exports.buildHashPayload = buildHashPayload;
67
68
  const buildSignature = async (payloadHash, secret) => encodeBase64(await hmac(payloadHash, secret));
@@ -3,6 +3,6 @@ export declare const sha256: (value: string) => Promise<string>;
3
3
  export declare const hmac: (value: string, secret: string, algorithm?: string) => Promise<string>;
4
4
  export declare const encodeBase64: (string: string) => string;
5
5
  export declare const decodeBase64: (string: string) => string;
6
- export declare const verifyToken: (token: string, secret: string) => Promise<string | undefined>;
6
+ export declare const verifyOrderSuccessToken: <T = unknown>(token: string, secret: string) => Promise<T | undefined>;
7
7
  export declare const buildHashPayload: (payload: unknown) => string;
8
8
  export declare const buildSignature: (payloadHash: string, secret: string) => Promise<string>;
@@ -50,12 +50,13 @@ export const decodeBase64 = (string) => {
50
50
  }
51
51
  return new TextDecoder().decode(base64ToBytes(string));
52
52
  };
53
- export const verifyToken = async (token, secret) => {
53
+ export const verifyOrderSuccessToken = async (token, secret) => {
54
54
  const [encodedPayload, signature] = token.split(".", 2);
55
55
  const expectedSignature = encodeBase64(await hmac(encodedPayload, secret));
56
56
  if (expectedSignature === signature) {
57
- return decodeBase64(encodedPayload);
57
+ return JSON.parse(decodeBase64(encodedPayload));
58
58
  }
59
+ return void 0;
59
60
  };
60
61
  export const buildHashPayload = (payload) => encodeBase64(JSON.stringify(payload));
61
62
  export const buildSignature = async (payloadHash, secret) => encodeBase64(await hmac(payloadHash, secret));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-core",
3
- "version": "7.64.3",
3
+ "version": "7.65.0",
4
4
  "description": "Collection of essential utilities to work with the Storefront API",
5
5
  "author": "SCAYLE Commerce Engine",
6
6
  "license": "MIT",
@@ -63,7 +63,6 @@
63
63
  "crypto-js": "^4.2.0",
64
64
  "hookable": "^5.5.3",
65
65
  "jose": "^5.6.3",
66
- "radash": "^12.1.0",
67
66
  "slugify": "^1.6.6",
68
67
  "ufo": "^1.5.3",
69
68
  "uncrypto": "^0.1.3",
@@ -72,18 +71,18 @@
72
71
  "devDependencies": {
73
72
  "@scayle/eslint-config-storefront": "4.3.0",
74
73
  "@types/crypto-js": "4.2.2",
75
- "@types/node": "20.16.1",
74
+ "@types/node": "20.16.5",
76
75
  "@types/webpack-env": "1.18.5",
77
76
  "@vitest/coverage-v8": "2.0.5",
78
77
  "dprint": "0.47.2",
79
- "eslint": "9.9.1",
78
+ "eslint": "9.10.0",
80
79
  "eslint-formatter-gitlab": "5.1.0",
81
80
  "publint": "0.2.10",
82
81
  "rimraf": "6.0.1",
83
82
  "ts-node": "10.9.2",
84
- "typescript": "5.5.4",
83
+ "typescript": "5.6.2",
85
84
  "unbuild": "2.0.0",
86
- "unstorage": "1.10.2",
85
+ "unstorage": "1.12.0",
87
86
  "vitest": "2.0.5"
88
87
  },
89
88
  "optionalDependencies": {