@scayle/storefront-core 8.7.1 → 8.8.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 +6 -0
- package/dist/rpc/methods/basket/basket.mjs +9 -4
- package/dist/rpc/methods/campaign.d.ts +13 -0
- package/dist/rpc/methods/campaign.mjs +23 -0
- package/dist/rpc/methods/checkout/checkout.mjs +4 -2
- package/dist/rpc/methods/index.d.ts +1 -0
- package/dist/rpc/methods/index.mjs +1 -0
- package/dist/rpc/methods/products.d.ts +4 -4
- package/dist/rpc/methods/products.mjs +19 -7
- package/dist/rpc/methods/variants.d.ts +1 -1
- package/dist/rpc/methods/variants.mjs +4 -1
- package/dist/rpc/methods/wishlist.mjs +7 -3
- package/dist/types/api/context.d.ts +3 -0
- package/dist/utils/campaign.d.ts +23 -0
- package/dist/utils/campaign.mjs +17 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/user.mjs +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { mergeBaskets as mergeBasketFunction } from "../../../utils/user.mjs";
|
|
10
10
|
import { unwrap } from "../../../utils/response.mjs";
|
|
11
11
|
import { wasAddedWithReducedQuantity } from "../../../utils/index.mjs";
|
|
12
|
+
import { getCampaignKey } from "../campaign.mjs";
|
|
12
13
|
const SAPI_ERROR_NAME = "SAPI ERROR";
|
|
13
14
|
function getWithParams(params, context) {
|
|
14
15
|
return params.with ?? context.withParams?.basket ?? MIN_WITH_PARAMS_BASKET;
|
|
@@ -31,7 +32,8 @@ export const addItemToBasket = async function addItemToBasket2({
|
|
|
31
32
|
"No Session found"
|
|
32
33
|
);
|
|
33
34
|
}
|
|
34
|
-
const {
|
|
35
|
+
const { sapiClient, basketKey } = context;
|
|
36
|
+
const campaignKey = await getCampaignKey(context);
|
|
35
37
|
const resolvedWith = getWithParams(
|
|
36
38
|
{ with: _with },
|
|
37
39
|
context
|
|
@@ -91,7 +93,8 @@ export const addItemsToBasket = async function addItemsToBasket2(params, context
|
|
|
91
93
|
"No Session found"
|
|
92
94
|
);
|
|
93
95
|
}
|
|
94
|
-
const {
|
|
96
|
+
const { sapiClient, basketKey } = context;
|
|
97
|
+
const campaignKey = await getCampaignKey(context);
|
|
95
98
|
const resolvedWith = getWithParams(params, context);
|
|
96
99
|
const itemsToBeAddedOrUpdated = params.items.map((item) => ({
|
|
97
100
|
variantId: item.variantId,
|
|
@@ -151,7 +154,8 @@ export const getBasket = async function getBasket2(options, context) {
|
|
|
151
154
|
"No Session found"
|
|
152
155
|
);
|
|
153
156
|
}
|
|
154
|
-
const { sapiClient,
|
|
157
|
+
const { sapiClient, basketKey } = context;
|
|
158
|
+
const campaignKey = await getCampaignKey(context);
|
|
155
159
|
const resolvedWith = getWithParams(
|
|
156
160
|
{ with: options },
|
|
157
161
|
context
|
|
@@ -183,7 +187,8 @@ export const removeItemFromBasket = async function removeItemFromBasket2(options
|
|
|
183
187
|
"No Session found"
|
|
184
188
|
);
|
|
185
189
|
}
|
|
186
|
-
const { sapiClient,
|
|
190
|
+
const { sapiClient, basketKey } = context;
|
|
191
|
+
const campaignKey = await getCampaignKey(context);
|
|
187
192
|
const resolvedWith = getWithParams(options, context);
|
|
188
193
|
const basket = await sapiClient.basket.deleteItem(
|
|
189
194
|
basketKey,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RpcContext } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* RPC method to retrieve the current campaign key.
|
|
4
|
+
* Used by other RPC methods which depend on a campaign key.
|
|
5
|
+
* Will return the key for the earliest active campaign.
|
|
6
|
+
*
|
|
7
|
+
* Uses SAPI's list-campaigns endpoint
|
|
8
|
+
* @see https://scayle.dev/en/api-guides/storefront-api/resources/campaigns/list-campaigns
|
|
9
|
+
*
|
|
10
|
+
* @param context The RPC Context
|
|
11
|
+
* @returns The current active campaign key.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getCampaignKey: (context: RpcContext) => Promise<string | undefined>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
campaignHasNotEnded,
|
|
3
|
+
sortCampaignsByDateAscending,
|
|
4
|
+
isCampaignActive
|
|
5
|
+
} from "../../utils/campaign.mjs";
|
|
6
|
+
export const getCampaignKey = async (context) => {
|
|
7
|
+
if (context.campaignKey) {
|
|
8
|
+
return context.campaignKey;
|
|
9
|
+
}
|
|
10
|
+
const { cached, sapiClient } = context;
|
|
11
|
+
const { campaigns } = await cached(async () => {
|
|
12
|
+
const { entities } = await sapiClient.campaigns.get();
|
|
13
|
+
return {
|
|
14
|
+
campaigns: entities.filter((campaign) => {
|
|
15
|
+
return campaignHasNotEnded(campaign);
|
|
16
|
+
}).sort(sortCampaignsByDateAscending)
|
|
17
|
+
};
|
|
18
|
+
}, {
|
|
19
|
+
cacheKeyPrefix: "get-campaignKey",
|
|
20
|
+
ttl: 5 * 60
|
|
21
|
+
})();
|
|
22
|
+
return campaigns.find(isCampaignActive)?.key;
|
|
23
|
+
};
|
|
@@ -3,6 +3,7 @@ import { hasSession } from "../../../types/index.mjs";
|
|
|
3
3
|
import { ErrorResponse } from "../../../errors/index.mjs";
|
|
4
4
|
import { HttpStatusCode, HttpStatusMessage } from "../../../constants/index.mjs";
|
|
5
5
|
import { getAccessToken } from "../user.mjs";
|
|
6
|
+
import { getCampaignKey } from "../campaign.mjs";
|
|
6
7
|
export const getCheckoutToken = async function getCheckoutToken2(jwtPayload = {}, context) {
|
|
7
8
|
if (!hasSession(context)) {
|
|
8
9
|
return new ErrorResponse(
|
|
@@ -28,14 +29,15 @@ export const getCheckoutToken = async function getCheckoutToken2(jwtPayload = {}
|
|
|
28
29
|
const secret = new TextEncoder().encode(context.checkout.secret);
|
|
29
30
|
const now = /* @__PURE__ */ new Date();
|
|
30
31
|
const { voucher, customData, preferredCollectionPoint, carrier } = jwtPayload;
|
|
32
|
+
const campaignKey = await getCampaignKey(context);
|
|
31
33
|
const checkoutJwt = await new SignJWT({
|
|
32
34
|
voucher,
|
|
33
35
|
customData,
|
|
34
36
|
preferredCollectionPoint,
|
|
35
37
|
carrier,
|
|
36
38
|
basketId: context.basketKey,
|
|
37
|
-
campaignKey
|
|
38
|
-
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.
|
|
39
|
+
campaignKey
|
|
40
|
+
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.8.0"}`).setProtectedHeader({ alg: "HS256", typ: "JWT" }).sign(secret);
|
|
39
41
|
return {
|
|
40
42
|
accessToken: refreshedAccessToken,
|
|
41
43
|
checkoutJwt
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './basket/basket';
|
|
2
2
|
export * from './brands';
|
|
3
3
|
export * from './categories';
|
|
4
|
+
export { getCampaignKey } from './campaign';
|
|
4
5
|
export * from './cbd';
|
|
5
6
|
export { getProductById, getProductsByIds, getProductsByReferenceKeys, getProductsCount, fetchAllFiltersForCategory, getFilters, getProductsByCategory, } from './products';
|
|
6
7
|
export * from './search';
|
|
@@ -20,9 +20,9 @@ export declare function resolveCategoryIdFromParams(context: RpcContext, params:
|
|
|
20
20
|
category: string | undefined;
|
|
21
21
|
categoryId: number | undefined;
|
|
22
22
|
}>;
|
|
23
|
-
export declare const getProductById: (options: FetchProductParams,
|
|
24
|
-
export declare const getProductsByIds: (options: FetchProductsByIdsParams,
|
|
25
|
-
export declare const getProductsByReferenceKeys: (options: FetchProductsByReferenceKeysParams,
|
|
23
|
+
export declare const getProductById: (options: FetchProductParams, context: RpcContext) => Promise<Response | Product>;
|
|
24
|
+
export declare const getProductsByIds: (options: FetchProductsByIdsParams, context: RpcContext) => Promise<Response | Product[]>;
|
|
25
|
+
export declare const getProductsByReferenceKeys: (options: FetchProductsByReferenceKeysParams, context: RpcContext) => Promise<Response | Product[]>;
|
|
26
26
|
export declare const getProductsCount: (params: FetchProductsCountParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
|
|
27
27
|
count: number;
|
|
28
28
|
}>;
|
|
@@ -31,7 +31,7 @@ export declare const fetchAllFiltersForCategory: ({ includedFilters, category }:
|
|
|
31
31
|
category: {
|
|
32
32
|
id?: number;
|
|
33
33
|
};
|
|
34
|
-
},
|
|
34
|
+
}, context: RpcContext) => Promise<string[]>;
|
|
35
35
|
export declare const getFilters: (params: FetchFiltersParams, context: RpcContext) => Promise<(string[] & ErrorResponse) | {
|
|
36
36
|
filters: FiltersEndpointResponseData;
|
|
37
37
|
unfilteredCount: number;
|
|
@@ -4,6 +4,7 @@ import { MINUTE } from "../../cache/index.mjs";
|
|
|
4
4
|
import { unwrap } from "../../utils/response.mjs";
|
|
5
5
|
import { mapSAPIFetchErrorToResponse } from "../../utils/sapi.mjs";
|
|
6
6
|
import { ErrorResponse } from "../../errors/index.mjs";
|
|
7
|
+
import { getCampaignKey } from "./campaign.mjs";
|
|
7
8
|
const MAX_PER_PAGE = 100;
|
|
8
9
|
const sanitizeAttributesForSAPI = ({
|
|
9
10
|
attributes,
|
|
@@ -34,7 +35,9 @@ export async function resolveCategoryIdFromParams(context, params) {
|
|
|
34
35
|
}
|
|
35
36
|
return { category, categoryId };
|
|
36
37
|
}
|
|
37
|
-
export const getProductById = async function getProductById2(options,
|
|
38
|
+
export const getProductById = async function getProductById2(options, context) {
|
|
39
|
+
const { sapiClient, cached, withParams } = context;
|
|
40
|
+
const campaignKey = await getCampaignKey(context);
|
|
38
41
|
return await cached(
|
|
39
42
|
mapSAPIFetchErrorToResponse(sapiClient.products.getById),
|
|
40
43
|
{
|
|
@@ -48,7 +51,9 @@ export const getProductById = async function getProductById2(options, { sapiClie
|
|
|
48
51
|
includeSellableForFree: options.includeSellableForFree
|
|
49
52
|
});
|
|
50
53
|
};
|
|
51
|
-
export const getProductsByIds = async function getProductsByIds2(options,
|
|
54
|
+
export const getProductsByIds = async function getProductsByIds2(options, context) {
|
|
55
|
+
const { sapiClient, cached, withParams } = context;
|
|
56
|
+
const campaignKey = await getCampaignKey(context);
|
|
52
57
|
return await cached(
|
|
53
58
|
mapSAPIFetchErrorToResponse(sapiClient.products.getByIds),
|
|
54
59
|
{
|
|
@@ -61,7 +66,9 @@ export const getProductsByIds = async function getProductsByIds2(options, { sapi
|
|
|
61
66
|
pricePromotionKey: options.pricePromotionKey
|
|
62
67
|
});
|
|
63
68
|
};
|
|
64
|
-
export const getProductsByReferenceKeys = async function getProductsByReferenceKeys2(options,
|
|
69
|
+
export const getProductsByReferenceKeys = async function getProductsByReferenceKeys2(options, context) {
|
|
70
|
+
const { sapiClient, cached, withParams } = context;
|
|
71
|
+
const campaignKey = await getCampaignKey(context);
|
|
65
72
|
return await cached(
|
|
66
73
|
mapSAPIFetchErrorToResponse(sapiClient.products.getByReferenceKeys),
|
|
67
74
|
{
|
|
@@ -82,7 +89,8 @@ export const getProductsCount = async function getProductsCount2(params, context
|
|
|
82
89
|
includeSellableForFree = false,
|
|
83
90
|
orFiltersOperator = void 0
|
|
84
91
|
} = params;
|
|
85
|
-
const { cached, sapiClient
|
|
92
|
+
const { cached, sapiClient } = context;
|
|
93
|
+
const campaignKey = await getCampaignKey(context);
|
|
86
94
|
const { categoryId } = await resolveCategoryIdFromParams(context, params);
|
|
87
95
|
const response = await getSanitizedAttributes(
|
|
88
96
|
context,
|
|
@@ -121,7 +129,9 @@ export const getProductsCount = async function getProductsCount2(params, context
|
|
|
121
129
|
count: productCount?.pagination.total
|
|
122
130
|
};
|
|
123
131
|
};
|
|
124
|
-
export const fetchAllFiltersForCategory = async function fetchAllFiltersForCategory2({ includedFilters = [], category },
|
|
132
|
+
export const fetchAllFiltersForCategory = async function fetchAllFiltersForCategory2({ includedFilters = [], category }, context) {
|
|
133
|
+
const { cached, sapiClient } = context;
|
|
134
|
+
const campaignKey = await getCampaignKey(context);
|
|
125
135
|
const fetchAndMapFiltersToSlugs = async () => {
|
|
126
136
|
const filtersFromSAPI = await cached(sapiClient.filters.get)({
|
|
127
137
|
where: { categoryId: category.id },
|
|
@@ -162,7 +172,8 @@ export const getFilters = async function getFilters2(params, context) {
|
|
|
162
172
|
includeSellableForFree = false,
|
|
163
173
|
orFiltersOperator
|
|
164
174
|
} = params;
|
|
165
|
-
const { cached, sapiClient
|
|
175
|
+
const { cached, sapiClient } = context;
|
|
176
|
+
const campaignKey = await getCampaignKey(context);
|
|
166
177
|
const { category, categoryId } = await resolveCategoryIdFromParams(
|
|
167
178
|
context,
|
|
168
179
|
params
|
|
@@ -241,7 +252,8 @@ export const getProductsByCategory = async function getProductsByCategory2(param
|
|
|
241
252
|
orFiltersOperator = void 0,
|
|
242
253
|
trackSearchAnalyticsEvent = void 0
|
|
243
254
|
} = params;
|
|
244
|
-
const { cached, sapiClient
|
|
255
|
+
const { cached, sapiClient } = context;
|
|
256
|
+
const campaignKey = await getCampaignKey(context);
|
|
245
257
|
const { category, categoryId } = await resolveCategoryIdFromParams(
|
|
246
258
|
context,
|
|
247
259
|
params
|
|
@@ -5,4 +5,4 @@ export interface FetchVariantsParams {
|
|
|
5
5
|
include?: ProductWith;
|
|
6
6
|
pricePromotionKey?: string;
|
|
7
7
|
}
|
|
8
|
-
export declare const getVariantById: ({ ids, include, pricePromotionKey }: FetchVariantsParams,
|
|
8
|
+
export declare const getVariantById: ({ ids, include, pricePromotionKey }: FetchVariantsParams, context: RpcContext) => Promise<Response | VariantDetail[]>;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { mapSAPIFetchErrorToResponse } from "../../utils/sapi.mjs";
|
|
2
|
+
import { getCampaignKey } from "./campaign.mjs";
|
|
2
3
|
const defaultWith = {
|
|
3
4
|
attributes: "all"
|
|
4
5
|
};
|
|
5
|
-
export const getVariantById = async function getVariantById2({ ids, include = defaultWith, pricePromotionKey = "default" },
|
|
6
|
+
export const getVariantById = async function getVariantById2({ ids, include = defaultWith, pricePromotionKey = "default" }, context) {
|
|
7
|
+
const { sapiClient, cached, withParams } = context;
|
|
8
|
+
const campaignKey = await getCampaignKey(context);
|
|
6
9
|
const resolvedWith = include ?? withParams?.variant ?? defaultWith;
|
|
7
10
|
return await cached(
|
|
8
11
|
mapSAPIFetchErrorToResponse(sapiClient.variants.getByIds),
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { unwrap } from "../../utils/response.mjs";
|
|
8
8
|
import { ErrorResponse } from "../../errors/index.mjs";
|
|
9
9
|
import { mapSAPIFetchErrorToResponse } from "../../utils/sapi.mjs";
|
|
10
|
+
import { getCampaignKey } from "./campaign.mjs";
|
|
10
11
|
function getWithParams(params, context) {
|
|
11
12
|
return params.with ?? context.withParams?.wishlist ?? MIN_WITH_PARAMS_WISHLIST;
|
|
12
13
|
}
|
|
@@ -18,7 +19,8 @@ export const getWishlist = async function getWishlist2(options, context) {
|
|
|
18
19
|
"No Session found"
|
|
19
20
|
);
|
|
20
21
|
}
|
|
21
|
-
const { sapiClient,
|
|
22
|
+
const { sapiClient, wishlistKey } = context;
|
|
23
|
+
const campaignKey = await getCampaignKey(context);
|
|
22
24
|
const resolvedWith = getWithParams({ with: options }, context);
|
|
23
25
|
return await mapSAPIFetchErrorToResponse(sapiClient.wishlist.get)(
|
|
24
26
|
wishlistKey,
|
|
@@ -37,7 +39,8 @@ export const addItemToWishlist = async function addItemToWishlist2(options, cont
|
|
|
37
39
|
"No Session found"
|
|
38
40
|
);
|
|
39
41
|
}
|
|
40
|
-
const { sapiClient,
|
|
42
|
+
const { sapiClient, wishlistKey } = context;
|
|
43
|
+
const campaignKey = await getCampaignKey(context);
|
|
41
44
|
const { productId, variantId } = options;
|
|
42
45
|
const resolvedWith = getWithParams(options, context);
|
|
43
46
|
const pricePromotionKey = resolvedWith?.pricePromotionKey ?? "";
|
|
@@ -73,7 +76,8 @@ export const removeItemFromWishlist = async function removeItemFromWishlist2(opt
|
|
|
73
76
|
"No Session found"
|
|
74
77
|
);
|
|
75
78
|
}
|
|
76
|
-
const { sapiClient,
|
|
79
|
+
const { sapiClient, wishlistKey } = context;
|
|
80
|
+
const campaignKey = await getCampaignKey(context);
|
|
77
81
|
const resolvedWith = getWithParams(options, context);
|
|
78
82
|
return await mapSAPIFetchErrorToResponse(sapiClient.wishlist.deleteItem)(
|
|
79
83
|
wishlistKey,
|
|
@@ -77,6 +77,9 @@ export type RpcContext = {
|
|
|
77
77
|
shopId: number;
|
|
78
78
|
domain?: string;
|
|
79
79
|
withParams?: WithParams;
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated Use the `getCampaignKey` RPC method instead.
|
|
82
|
+
*/
|
|
80
83
|
campaignKey?: string;
|
|
81
84
|
destroySessionsForUserId: (userId: number, sessionsToKeep?: string[]) => Promise<void>;
|
|
82
85
|
generateBasketKeyForUserId: (userId: string) => Promise<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Campaign } from '@scayle/storefront-api';
|
|
2
|
+
/**
|
|
3
|
+
* Determine if a campaign is active for the current date
|
|
4
|
+
*
|
|
5
|
+
* @param campaign the campaign to test
|
|
6
|
+
* @returns True when the current datetime is within the campaign's timeframe, false otherwise
|
|
7
|
+
*/
|
|
8
|
+
export declare const isCampaignActive: (campaign?: Campaign) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Determine if a campaign has ended based on the current datetime
|
|
11
|
+
*
|
|
12
|
+
* @param campaign
|
|
13
|
+
* @returns True if the campaign's end date is later than the current datetime, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
export declare const campaignHasNotEnded: (campaign: Campaign) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Comparison function for campaigns based on their start date. To be used with Array.prototype.sort()
|
|
18
|
+
*
|
|
19
|
+
* @param a The first campaign for comparison
|
|
20
|
+
* @param b The second campaign for comparison
|
|
21
|
+
* @returns A positive value when a should come before b, negative value when b should come before a, or 0 when they are considered equal
|
|
22
|
+
*/
|
|
23
|
+
export declare const sortCampaignsByDateAscending: (a: Campaign, b: Campaign) => number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const isCampaignActive = (campaign) => {
|
|
2
|
+
if (!campaign) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
const timeNow = Date.now();
|
|
6
|
+
const campaignStart = new Date(campaign.start_at).getTime();
|
|
7
|
+
const hasStarted = timeNow >= campaignStart;
|
|
8
|
+
const campaignEnd = new Date(campaign.end_at).getTime();
|
|
9
|
+
const hasEnded = timeNow >= campaignEnd;
|
|
10
|
+
return hasStarted && !hasEnded;
|
|
11
|
+
};
|
|
12
|
+
export const campaignHasNotEnded = (campaign) => {
|
|
13
|
+
return new Date(campaign.end_at).getTime() > Date.now();
|
|
14
|
+
};
|
|
15
|
+
export const sortCampaignsByDateAscending = (a, b) => {
|
|
16
|
+
return new Date(a.start_at).getTime() - new Date(b.start_at).getTime();
|
|
17
|
+
};
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.mjs
CHANGED
package/dist/utils/user.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ExistingItemHandling } from "@scayle/storefront-api";
|
|
2
|
+
import { getCampaignKey } from "../rpc/methods/index.mjs";
|
|
2
3
|
export const mergeBaskets = async (fromBasketKey, toBasketKey, withOptions, context) => {
|
|
3
|
-
const { sapiClient
|
|
4
|
+
const { sapiClient } = context;
|
|
5
|
+
const campaignKey = await getCampaignKey(context);
|
|
4
6
|
const fromOriginBasket = await sapiClient.basket.get(fromBasketKey, {
|
|
5
7
|
with: withOptions,
|
|
6
8
|
campaignKey,
|
|
@@ -43,7 +45,8 @@ export const mergeBaskets = async (fromBasketKey, toBasketKey, withOptions, cont
|
|
|
43
45
|
}
|
|
44
46
|
};
|
|
45
47
|
export const mergeWishlists = async (fromWishlistKey, toWishlistKey, withOptions, context) => {
|
|
46
|
-
const { sapiClient
|
|
48
|
+
const { sapiClient } = context;
|
|
49
|
+
const campaignKey = await getCampaignKey(context);
|
|
47
50
|
const oldWishlist = await sapiClient.wishlist.get(fromWishlistKey, {
|
|
48
51
|
with: withOptions,
|
|
49
52
|
campaignKey
|