@scayle/storefront-core 8.61.3 → 8.62.1
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,40 @@
|
|
|
1
1
|
# @scayle/storefront-core
|
|
2
2
|
|
|
3
|
+
## 8.62.1
|
|
4
|
+
|
|
5
|
+
No changes in this release.
|
|
6
|
+
|
|
7
|
+
## 8.62.0
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- **\[Promotions\]** Added customer-segmented promotion fetches when a valid session token is present.
|
|
12
|
+
|
|
13
|
+
`getPromotions`, `getCurrentPromotions`, and `getPromotionsByIds` accept a `segmentation` flag. When it is `true` and the request has a non-expired access token, the handlers call the Storefront API with `customerToken` and skip the shared cache so results match the logged-in customer. When it is `false`, handlers use the cached anonymous promotion list so customer-specific promotions are not stored in shared cache responses.
|
|
14
|
+
|
|
15
|
+
**\[BREAKING\]** `getPromotionsByIds` now expects `{ ids: string[], segmentation: boolean }` instead of a bare `string[]` array.
|
|
16
|
+
- Before (custom RPC handler via `context.callRpc`):
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const promotions = await context.callRpc?.('getPromotionsByIds', [
|
|
20
|
+
'promo-1',
|
|
21
|
+
'promo-2',
|
|
22
|
+
])
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- After:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const promotions = await context.callRpc?.('getPromotionsByIds', {
|
|
29
|
+
ids: ['promo-1', 'promo-2'],
|
|
30
|
+
segmentation: true,
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Promotion list handlers use `POST` instead of `GET` so `segmentation` and `customerToken` are not sent in the URL.
|
|
35
|
+
|
|
36
|
+
**\[User\]** Exported `getValidatedAccessToken` to return a JWT only when it is present and not expired. Basket merge and promotion handlers use it when passing `customerToken` to the Storefront API.
|
|
37
|
+
|
|
3
38
|
## 8.61.3
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -41,7 +41,7 @@ export const getCheckoutToken = defineRpcHandler(
|
|
|
41
41
|
...customData,
|
|
42
42
|
...orderCustomData
|
|
43
43
|
}
|
|
44
|
-
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.
|
|
44
|
+
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.62.1"}`).setProtectedHeader({ alg: "HS256", typ: "JWT" }).sign(secret);
|
|
45
45
|
return {
|
|
46
46
|
accessToken: refreshedAccessToken,
|
|
47
47
|
checkoutJwt
|
|
@@ -2,45 +2,67 @@ import type { PromotionsParams, PromotionsResponseData, RpcHandler } from '../..
|
|
|
2
2
|
/**
|
|
3
3
|
* Retrieves promotions based on provided parameters.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Uses the Storefront cache (`cached()`) with a `getPromotions` key prefix to improve performance.
|
|
6
6
|
* Cached entries are returned if found; otherwise, data is fetched and cached.
|
|
7
7
|
*
|
|
8
|
+
* When `segmentation` is `true` and the request includes a valid customer access token, promotions are
|
|
9
|
+
* fetched directly from the Storefront API and are not cached.
|
|
10
|
+
*
|
|
8
11
|
* @param params The parameters for retrieving promotions.
|
|
9
12
|
* @param params.pagination Pagination settings.
|
|
10
13
|
* @param params.pagination.page Page number.
|
|
11
14
|
* @param params.pagination.perPage Number of items per page.
|
|
15
|
+
* @param params.segmentation When `true`, fetches customer-segmented promotions without caching.
|
|
16
|
+
* Defaults to `false`.
|
|
12
17
|
* @param context The RPC context.
|
|
13
18
|
*
|
|
14
19
|
* @returns A Promise that resolves with the promotion data.
|
|
15
20
|
* It will return an `ErrorResponse` if the The Storefront API request fails.
|
|
16
21
|
*/
|
|
17
|
-
export declare const getPromotions: RpcHandler<Omit<PromotionsParams, 'ids'
|
|
22
|
+
export declare const getPromotions: RpcHandler<Omit<PromotionsParams, 'ids' | 'customerToken'> & {
|
|
23
|
+
segmentation: boolean;
|
|
24
|
+
}, PromotionsResponseData>;
|
|
18
25
|
/**
|
|
19
26
|
* Retrieves currently active promotions.
|
|
20
27
|
*
|
|
21
|
-
*
|
|
28
|
+
* Uses the Storefront cache (`cached()`) with a `getPromotions` key prefix to improve performance.
|
|
22
29
|
* Cached entries are returned if found; otherwise, data is fetched and cached.
|
|
23
30
|
*
|
|
31
|
+
* When `segmentation` is `true` and the request includes a valid customer access token, promotions are
|
|
32
|
+
* fetched directly from the Storefront API and are not cached.
|
|
33
|
+
*
|
|
24
34
|
* @param params The parameters for retrieving promotions.
|
|
25
35
|
* @param params.pagination Pagination settings.
|
|
26
36
|
* @param params.pagination.page Page number.
|
|
27
37
|
* @param params.pagination.perPage Number of items per page.
|
|
38
|
+
* @param params.segmentation When `true`, fetches customer-segmented promotions without caching.
|
|
39
|
+
* Defaults to `false`.
|
|
28
40
|
* @param context The RPC context.
|
|
29
41
|
*
|
|
30
42
|
* @returns A Promise that resolves with the current promotion data.
|
|
31
43
|
* It will return an `ErrorResponse` if the The Storefront API request fails.
|
|
32
44
|
*/
|
|
33
|
-
export declare const getCurrentPromotions: RpcHandler<Omit<PromotionsParams, 'ids' | 'activeAt'
|
|
45
|
+
export declare const getCurrentPromotions: RpcHandler<Omit<PromotionsParams, 'ids' | 'activeAt' | 'customerToken'> & {
|
|
46
|
+
segmentation: boolean;
|
|
47
|
+
}, PromotionsResponseData>;
|
|
34
48
|
/**
|
|
35
49
|
* Retrieves promotions by their IDs.
|
|
36
50
|
*
|
|
37
|
-
*
|
|
51
|
+
* Uses the Storefront cache (`cached()`) with a `getByIds-promotions` key prefix to improve performance.
|
|
38
52
|
* Cached entries are returned if found; otherwise, data is fetched and cached.
|
|
39
53
|
*
|
|
40
|
-
*
|
|
54
|
+
* When `segmentation` is `true` and the request includes a valid customer access token, promotions are
|
|
55
|
+
* fetched directly from the Storefront API and are not cached.
|
|
56
|
+
*
|
|
57
|
+
* @param params Request parameters.
|
|
58
|
+
* @param params.ids Promotion IDs to retrieve.
|
|
59
|
+
* @param params.segmentation When `true`, fetches customer-segmented promotions without caching.
|
|
41
60
|
* @param context The RPC context.
|
|
42
61
|
*
|
|
43
62
|
* @returns A Promise that resolves with the promotion data.
|
|
44
63
|
* It will return an `ErrorResponse` if the The Storefront API request fails.
|
|
45
64
|
*/
|
|
46
|
-
export declare const getPromotionsByIds: RpcHandler<
|
|
65
|
+
export declare const getPromotionsByIds: RpcHandler<{
|
|
66
|
+
ids: string[];
|
|
67
|
+
segmentation: boolean;
|
|
68
|
+
}, PromotionsResponseData>;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from "../../constants/index.mjs";
|
|
5
5
|
import { mapSAPIFetchErrorToResponse } from "../../utils/sapi.mjs";
|
|
6
6
|
import { defineRpcHandler } from "../../utils/index.mjs";
|
|
7
|
+
import { getValidatedAccessToken } from "../../utils/user.mjs";
|
|
7
8
|
const setPaginationDefault = (pagination) => {
|
|
8
9
|
return {
|
|
9
10
|
page: pagination?.page || PROMOTION_PAGE_DEFAULT,
|
|
@@ -11,42 +12,69 @@ const setPaginationDefault = (pagination) => {
|
|
|
11
12
|
};
|
|
12
13
|
};
|
|
13
14
|
export const getPromotions = defineRpcHandler(
|
|
14
|
-
async (params = {}, context) => {
|
|
15
|
+
async (params = { segmentation: false }, context) => {
|
|
15
16
|
const { sapiClient, cached } = context;
|
|
17
|
+
const { segmentation, ...promotionsParams } = params;
|
|
18
|
+
const customerToken = getValidatedAccessToken(context.accessToken);
|
|
19
|
+
if (segmentation && customerToken) {
|
|
20
|
+
return mapSAPIFetchErrorToResponse(sapiClient.promotions.get)({
|
|
21
|
+
...promotionsParams,
|
|
22
|
+
pagination: setPaginationDefault(params.pagination),
|
|
23
|
+
customerToken
|
|
24
|
+
});
|
|
25
|
+
}
|
|
16
26
|
return await cached(
|
|
17
27
|
mapSAPIFetchErrorToResponse(sapiClient.promotions.get),
|
|
18
28
|
{
|
|
19
29
|
cacheKeyPrefix: "getPromotions"
|
|
20
30
|
}
|
|
21
31
|
)({
|
|
22
|
-
...
|
|
32
|
+
...promotionsParams,
|
|
23
33
|
pagination: setPaginationDefault(params.pagination)
|
|
24
34
|
});
|
|
25
35
|
},
|
|
26
|
-
{ method: "
|
|
36
|
+
{ method: "POST" }
|
|
27
37
|
);
|
|
28
38
|
export const getCurrentPromotions = defineRpcHandler(
|
|
29
|
-
async (params = {}, context) => {
|
|
39
|
+
async (params = { segmentation: false }, context) => {
|
|
30
40
|
const { sapiClient, cached } = context;
|
|
31
41
|
const now = /* @__PURE__ */ new Date();
|
|
32
42
|
now.setSeconds(0, 0);
|
|
33
43
|
const activeAt = now.toISOString();
|
|
44
|
+
const { segmentation, ...promotionsParams } = params;
|
|
45
|
+
const customerToken = getValidatedAccessToken(context.accessToken);
|
|
46
|
+
if (segmentation && customerToken) {
|
|
47
|
+
return mapSAPIFetchErrorToResponse(sapiClient.promotions.get)({
|
|
48
|
+
...promotionsParams,
|
|
49
|
+
activeAt,
|
|
50
|
+
pagination: setPaginationDefault(params.pagination),
|
|
51
|
+
customerToken
|
|
52
|
+
});
|
|
53
|
+
}
|
|
34
54
|
return await cached(
|
|
35
55
|
mapSAPIFetchErrorToResponse(sapiClient.promotions.get),
|
|
36
56
|
{
|
|
37
57
|
cacheKeyPrefix: "getPromotions"
|
|
38
58
|
}
|
|
39
59
|
)({
|
|
40
|
-
...
|
|
60
|
+
...promotionsParams,
|
|
41
61
|
activeAt,
|
|
42
62
|
pagination: setPaginationDefault(params.pagination)
|
|
43
63
|
});
|
|
44
64
|
},
|
|
45
|
-
{ method: "
|
|
65
|
+
{ method: "POST" }
|
|
46
66
|
);
|
|
47
67
|
export const getPromotionsByIds = defineRpcHandler(
|
|
48
|
-
async (
|
|
68
|
+
async (params, context) => {
|
|
49
69
|
const { sapiClient, cached } = context;
|
|
70
|
+
const { ids, segmentation } = params;
|
|
71
|
+
const customerToken = getValidatedAccessToken(context.accessToken);
|
|
72
|
+
if (segmentation && customerToken) {
|
|
73
|
+
return mapSAPIFetchErrorToResponse(sapiClient.promotions.getByIds)(
|
|
74
|
+
ids,
|
|
75
|
+
customerToken
|
|
76
|
+
);
|
|
77
|
+
}
|
|
50
78
|
return await cached(
|
|
51
79
|
mapSAPIFetchErrorToResponse(sapiClient.promotions.getByIds),
|
|
52
80
|
{
|
|
@@ -54,5 +82,5 @@ export const getPromotionsByIds = defineRpcHandler(
|
|
|
54
82
|
}
|
|
55
83
|
)(ids);
|
|
56
84
|
},
|
|
57
|
-
{ method: "
|
|
85
|
+
{ method: "POST" }
|
|
58
86
|
);
|
package/dist/utils/user.mjs
CHANGED
|
@@ -6,7 +6,7 @@ export const getValidatedAccessToken = (accessToken) => {
|
|
|
6
6
|
}
|
|
7
7
|
const payload = decodeJwt(accessToken);
|
|
8
8
|
if (!payload.exp || payload.exp < Date.now() / 1e3) {
|
|
9
|
-
return;
|
|
9
|
+
return void 0;
|
|
10
10
|
}
|
|
11
11
|
return accessToken;
|
|
12
12
|
};
|
|
@@ -51,7 +51,9 @@ export const mergeBaskets = async (fromBasketKey, toBasketKey, withOptions, cont
|
|
|
51
51
|
}
|
|
52
52
|
);
|
|
53
53
|
fromBasket.items.map(async (item) => {
|
|
54
|
-
return await sapiClient.basket.deleteItem(fromBasketKey, item.key
|
|
54
|
+
return await sapiClient.basket.deleteItem(fromBasketKey, item.key, {
|
|
55
|
+
customerToken: getValidatedAccessToken(context.accessToken) ?? void 0
|
|
56
|
+
});
|
|
55
57
|
});
|
|
56
58
|
return mergedBasket;
|
|
57
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/storefront-core",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.62.1",
|
|
4
4
|
"description": "Collection of essential utilities to work with the Storefront API",
|
|
5
5
|
"author": "SCAYLE Commerce Engine",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"fishery": "^2.2.3"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@scayle/storefront-api": "^19.
|
|
44
|
+
"@scayle/storefront-api": "^19.1.2",
|
|
45
45
|
"@scayle/unstorage-scayle-kv-driver": "^2.1.0",
|
|
46
46
|
"crypto-js": "^4.2.0",
|
|
47
47
|
"hookable": "^5.5.3",
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
"@types/crypto-js": "4.2.2",
|
|
57
57
|
"@types/node": "24.12.2",
|
|
58
58
|
"@types/webpack-env": "1.18.8",
|
|
59
|
-
"@vitest/coverage-v8": "4.1.
|
|
59
|
+
"@vitest/coverage-v8": "4.1.9",
|
|
60
60
|
"eslint-formatter-gitlab": "7.1.0",
|
|
61
|
-
"eslint": "10.
|
|
61
|
+
"eslint": "10.5.0",
|
|
62
62
|
"fishery": "2.4.0",
|
|
63
63
|
"publint": "0.3.21",
|
|
64
64
|
"typescript": "6.0.3",
|
|
65
65
|
"unbuild": "3.6.1",
|
|
66
66
|
"unstorage": "1.17.5",
|
|
67
|
-
"vitest": "4.1.
|
|
67
|
+
"vitest": "4.1.9",
|
|
68
68
|
"@scayle/vitest-config-storefront": "1.0.0"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|