@scayle/storefront-core 8.60.1 → 8.61.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 +124 -87
- package/dist/api/INFO.md +1 -1
- package/dist/cache/providers/unstorage.mjs +3 -1
- package/dist/constants/withParameters.mjs +16 -2
- package/dist/helpers/productHelpers.mjs +3 -1
- package/dist/helpers/sanitizationHelpers.mjs +4 -1
- package/dist/rpc/methods/basket/basket.mjs +10 -9
- package/dist/rpc/methods/brands.mjs +2 -2
- package/dist/rpc/methods/campaign.mjs +2 -2
- package/dist/rpc/methods/categories.mjs +5 -5
- package/dist/rpc/methods/cbd.mjs +1 -1
- package/dist/rpc/methods/checkout/checkout.mjs +2 -2
- package/dist/rpc/methods/checkout/order.mjs +2 -2
- package/dist/rpc/methods/checkout/shopUser.mjs +2 -2
- package/dist/rpc/methods/checkout/shopUserAddresses.mjs +3 -1
- package/dist/rpc/methods/navigationTrees.mjs +3 -3
- package/dist/rpc/methods/oauth/idp.mjs +2 -2
- package/dist/rpc/methods/products.mjs +65 -61
- package/dist/rpc/methods/promotion.mjs +3 -3
- package/dist/rpc/methods/search.mjs +2 -2
- package/dist/rpc/methods/session.mjs +7 -7
- package/dist/rpc/methods/shopConfiguration.mjs +1 -1
- package/dist/rpc/methods/user.mjs +6 -4
- package/dist/rpc/methods/variants.mjs +1 -1
- package/dist/rpc/methods/wishlist.mjs +14 -6
- package/dist/types/api/rpc.d.ts +15 -2
- package/dist/utils/hash.mjs +7 -2
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/rpc.d.ts +23 -6
- package/dist/utils/rpc.mjs +4 -3
- package/package.json +12 -18
|
@@ -40,9 +40,9 @@ export const getCheckoutToken = defineRpcHandler(async (jwtPayload = {}, context
|
|
|
40
40
|
...customData,
|
|
41
41
|
...orderCustomData
|
|
42
42
|
}
|
|
43
|
-
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.
|
|
43
|
+
}).setIssuedAt(now).setNotBefore(now).setExpirationTime("1h").setIssuer(`${"@scayle/storefront-core"}@${"8.61.1"}`).setProtectedHeader({ alg: "HS256", typ: "JWT" }).sign(secret);
|
|
44
44
|
return {
|
|
45
45
|
accessToken: refreshedAccessToken,
|
|
46
46
|
checkoutJwt
|
|
47
47
|
};
|
|
48
|
-
});
|
|
48
|
+
}, { method: "POST" });
|
|
@@ -56,7 +56,7 @@ export const updateShopUser = defineRpcHandler(async (payload, context) => {
|
|
|
56
56
|
"Error while updating user information"
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
|
-
});
|
|
59
|
+
}, { method: "PUT" });
|
|
60
60
|
export const updatePassword = defineRpcHandler(async ({ oldPassword, newPassword }, context) => {
|
|
61
61
|
const shopUser = context.user;
|
|
62
62
|
const oauthEnabled = context.oauth?.apiHost && context.oauth?.clientId && context.oauth?.clientSecret;
|
|
@@ -121,4 +121,4 @@ export const updatePassword = defineRpcHandler(async ({ oldPassword, newPassword
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
return { user: shopUser };
|
|
124
|
-
});
|
|
124
|
+
}, { method: "PUT" });
|
|
@@ -5,6 +5,8 @@ const getShopUserAddresses = defineRpcHandler(
|
|
|
5
5
|
const shopId = context.shopId;
|
|
6
6
|
const client = new CustomerAPIClient(context);
|
|
7
7
|
return (await client.getAddresses(shopId)).entities;
|
|
8
|
-
}
|
|
8
|
+
},
|
|
9
|
+
// We use POST here to prevent user data to be leaking into caches.
|
|
10
|
+
{ method: "POST" }
|
|
9
11
|
);
|
|
10
12
|
export { getShopUserAddresses };
|
|
@@ -6,13 +6,13 @@ export const fetchAllNavigationTrees = defineRpcHandler(async ({ params }, conte
|
|
|
6
6
|
return await cached(navigation.getAll, {
|
|
7
7
|
cacheKeyPrefix: "getAll-navigation-trees"
|
|
8
8
|
})(params);
|
|
9
|
-
});
|
|
9
|
+
}, { method: "GET" });
|
|
10
10
|
export const fetchNavigationTreeById = defineRpcHandler(async ({ treeId, params }, context) => {
|
|
11
11
|
const { sapiClient: { navigation }, cached } = context;
|
|
12
12
|
return await cached(navigation.getById, {
|
|
13
13
|
cacheKeyPrefix: `getById-navigation-trees-${treeId}`
|
|
14
14
|
})(treeId, params);
|
|
15
|
-
});
|
|
15
|
+
}, { method: "GET" });
|
|
16
16
|
export const fetchNavigationTreeByName = defineRpcHandler(async ({ treeName, params }, context) => {
|
|
17
17
|
const { sapiClient: { navigation }, cached } = context;
|
|
18
18
|
return await cached(
|
|
@@ -34,4 +34,4 @@ export const fetchNavigationTreeByName = defineRpcHandler(async ({ treeName, par
|
|
|
34
34
|
cacheKeyPrefix: `getByName-navigation-trees-${treeName}`
|
|
35
35
|
}
|
|
36
36
|
)(treeName, params);
|
|
37
|
-
});
|
|
37
|
+
}, { method: "GET" });
|
|
@@ -46,7 +46,7 @@ export const getExternalIdpRedirect = defineRpcHandler(async ({ queryParams, aut
|
|
|
46
46
|
})
|
|
47
47
|
);
|
|
48
48
|
return Object.fromEntries(results);
|
|
49
|
-
});
|
|
49
|
+
}, { method: "GET" });
|
|
50
50
|
export const handleIDPLoginCallback = defineRpcHandler(async (payload, context) => {
|
|
51
51
|
if (!hasSession(context)) {
|
|
52
52
|
return new ErrorResponse(
|
|
@@ -61,4 +61,4 @@ export const handleIDPLoginCallback = defineRpcHandler(async (payload, context)
|
|
|
61
61
|
return {
|
|
62
62
|
message: "success"
|
|
63
63
|
};
|
|
64
|
-
});
|
|
64
|
+
}, { method: "POST" });
|
|
@@ -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 { defineRpcHandler } from "../../utils/index.mjs";
|
|
7
8
|
const MAX_PER_PAGE = 100;
|
|
8
9
|
const sanitizeAttributesForSAPI = ({
|
|
9
10
|
attributes,
|
|
@@ -32,7 +33,7 @@ export async function resolveCategoryIdFromParams(context, params) {
|
|
|
32
33
|
}
|
|
33
34
|
return { category, categoryId };
|
|
34
35
|
}
|
|
35
|
-
export const getProductById = async
|
|
36
|
+
export const getProductById = defineRpcHandler(async (options, context) => {
|
|
36
37
|
const { sapiClient, cached, withParams } = context;
|
|
37
38
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
38
39
|
return await cached(
|
|
@@ -47,8 +48,8 @@ export const getProductById = async function getProductById2(options, context) {
|
|
|
47
48
|
pricePromotionKey: options.pricePromotionKey,
|
|
48
49
|
includeSellableForFree: options.includeSellableForFree
|
|
49
50
|
});
|
|
50
|
-
};
|
|
51
|
-
export const getProductsByIds = async
|
|
51
|
+
}, { method: "GET" });
|
|
52
|
+
export const getProductsByIds = defineRpcHandler(async (options, context) => {
|
|
52
53
|
const { sapiClient, cached, withParams } = context;
|
|
53
54
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
54
55
|
return await cached(
|
|
@@ -62,8 +63,8 @@ export const getProductsByIds = async function getProductsByIds2(options, contex
|
|
|
62
63
|
campaignKey,
|
|
63
64
|
pricePromotionKey: options.pricePromotionKey
|
|
64
65
|
});
|
|
65
|
-
};
|
|
66
|
-
export const getProductsByReferenceKeys = async
|
|
66
|
+
}, { method: "GET" });
|
|
67
|
+
export const getProductsByReferenceKeys = defineRpcHandler(async (options, context) => {
|
|
67
68
|
const { sapiClient, cached, withParams } = context;
|
|
68
69
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
69
70
|
return await cached(
|
|
@@ -77,63 +78,66 @@ export const getProductsByReferenceKeys = async function getProductsByReferenceK
|
|
|
77
78
|
campaignKey,
|
|
78
79
|
pricePromotionKey: options.pricePromotionKey
|
|
79
80
|
});
|
|
80
|
-
};
|
|
81
|
-
export const getProductsCount =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
attributes || [],
|
|
97
|
-
includedFilters,
|
|
98
|
-
includeSoldOut,
|
|
99
|
-
includeSellableForFree,
|
|
100
|
-
orFiltersOperator
|
|
101
|
-
);
|
|
102
|
-
if (response instanceof ErrorResponse) {
|
|
103
|
-
return response;
|
|
104
|
-
}
|
|
105
|
-
const sanitizedAttributes = response;
|
|
106
|
-
const productCount = await cached(sapiClient.products.query, {
|
|
107
|
-
ttl: 15 * MINUTE,
|
|
108
|
-
cacheKeyPrefix: "products-query"
|
|
109
|
-
})({
|
|
110
|
-
where: {
|
|
111
|
-
...filter,
|
|
81
|
+
}, { method: "GET" });
|
|
82
|
+
export const getProductsCount = defineRpcHandler(
|
|
83
|
+
async (params, context) => {
|
|
84
|
+
const {
|
|
85
|
+
includedFilters,
|
|
86
|
+
where = void 0,
|
|
87
|
+
includeSoldOut = false,
|
|
88
|
+
includeSellableForFree = false,
|
|
89
|
+
orFiltersOperator = void 0
|
|
90
|
+
} = params;
|
|
91
|
+
const { cached, sapiClient } = context;
|
|
92
|
+
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
93
|
+
const { categoryId } = await resolveCategoryIdFromParams(context, params);
|
|
94
|
+
const { attributes, whitelistAttributes, ...filter } = where || {};
|
|
95
|
+
const response = await getSanitizedAttributes(
|
|
96
|
+
context,
|
|
112
97
|
categoryId,
|
|
113
|
-
attributes
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
98
|
+
attributes || [],
|
|
99
|
+
includedFilters,
|
|
100
|
+
includeSoldOut,
|
|
101
|
+
includeSellableForFree,
|
|
102
|
+
orFiltersOperator
|
|
103
|
+
);
|
|
104
|
+
if (response instanceof ErrorResponse) {
|
|
105
|
+
return response;
|
|
106
|
+
}
|
|
107
|
+
const sanitizedAttributes = response;
|
|
108
|
+
const productCount = await cached(sapiClient.products.query, {
|
|
109
|
+
ttl: 15 * MINUTE,
|
|
110
|
+
cacheKeyPrefix: "products-query"
|
|
111
|
+
})({
|
|
112
|
+
where: {
|
|
113
|
+
...filter,
|
|
114
|
+
categoryId,
|
|
115
|
+
attributes: [
|
|
116
|
+
...sanitizedAttributes,
|
|
117
|
+
...whitelistAttributes || []
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
pagination: {
|
|
121
|
+
perPage: 1
|
|
122
|
+
},
|
|
123
|
+
campaignKey,
|
|
124
|
+
includeSellableForFree,
|
|
125
|
+
includeSoldOut,
|
|
126
|
+
orFiltersOperator
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
count: productCount?.pagination.total
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
{ method: "GET" }
|
|
133
|
+
);
|
|
134
|
+
export const fetchAllFiltersForCategory = defineRpcHandler(async ({
|
|
131
135
|
includedFilters = [],
|
|
132
136
|
category,
|
|
133
137
|
includeSoldOut,
|
|
134
138
|
includeSellableForFree,
|
|
135
139
|
orFiltersOperator
|
|
136
|
-
}, context) {
|
|
140
|
+
}, context) => {
|
|
137
141
|
const { cached, sapiClient } = context;
|
|
138
142
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
139
143
|
const fetchAndMapFiltersToSlugs = async () => {
|
|
@@ -152,7 +156,7 @@ export const fetchAllFiltersForCategory = async function fetchAllFiltersForCateg
|
|
|
152
156
|
// cached for 4 hours
|
|
153
157
|
cacheKey: `filters-for-category-${category.id}`
|
|
154
158
|
})();
|
|
155
|
-
};
|
|
159
|
+
}, { method: "GET" });
|
|
156
160
|
async function getSanitizedAttributes(context, categoryId, attributes, includedFilters, includeSoldOut, includeSellableForFree, orFiltersOperator) {
|
|
157
161
|
const response = await fetchAllFiltersForCategory(
|
|
158
162
|
{
|
|
@@ -174,7 +178,7 @@ async function getSanitizedAttributes(context, categoryId, attributes, includedF
|
|
|
174
178
|
includedFilters
|
|
175
179
|
});
|
|
176
180
|
}
|
|
177
|
-
export const getFilters = async
|
|
181
|
+
export const getFilters = defineRpcHandler(async (params, context) => {
|
|
178
182
|
const {
|
|
179
183
|
includedFilters,
|
|
180
184
|
where = void 0,
|
|
@@ -245,8 +249,8 @@ export const getFilters = async function getFilters2(params, context) {
|
|
|
245
249
|
filters,
|
|
246
250
|
unfilteredCount: productCount?.pagination.total
|
|
247
251
|
};
|
|
248
|
-
};
|
|
249
|
-
export const getProductsByCategory = async
|
|
252
|
+
}, { method: "GET" });
|
|
253
|
+
export const getProductsByCategory = defineRpcHandler(async (params, context) => {
|
|
250
254
|
const {
|
|
251
255
|
includedFilters,
|
|
252
256
|
cache,
|
|
@@ -321,4 +325,4 @@ export const getProductsByCategory = async function getProductsByCategory2(param
|
|
|
321
325
|
...pagination
|
|
322
326
|
}
|
|
323
327
|
};
|
|
324
|
-
};
|
|
328
|
+
}, { method: "GET" });
|
|
@@ -18,7 +18,7 @@ export const getPromotions = defineRpcHandler(async (params = {}, context) => {
|
|
|
18
18
|
...params,
|
|
19
19
|
pagination: setPaginationDefault(params.pagination)
|
|
20
20
|
});
|
|
21
|
-
});
|
|
21
|
+
}, { method: "GET" });
|
|
22
22
|
export const getCurrentPromotions = defineRpcHandler(async (params = {}, context) => {
|
|
23
23
|
const { sapiClient, cached } = context;
|
|
24
24
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -31,7 +31,7 @@ export const getCurrentPromotions = defineRpcHandler(async (params = {}, context
|
|
|
31
31
|
activeAt,
|
|
32
32
|
pagination: setPaginationDefault(params.pagination)
|
|
33
33
|
});
|
|
34
|
-
});
|
|
34
|
+
}, { method: "GET" });
|
|
35
35
|
export const getPromotionsByIds = defineRpcHandler(async (ids, context) => {
|
|
36
36
|
const { sapiClient, cached } = context;
|
|
37
37
|
return await cached(
|
|
@@ -40,4 +40,4 @@ export const getPromotionsByIds = defineRpcHandler(async (ids, context) => {
|
|
|
40
40
|
cacheKeyPrefix: "getByIds-promotions"
|
|
41
41
|
}
|
|
42
42
|
)(ids);
|
|
43
|
-
});
|
|
43
|
+
}, { method: "GET" });
|
|
@@ -9,7 +9,7 @@ export const getSearchSuggestions = defineRpcHandler(async ({ term, with: _with,
|
|
|
9
9
|
with: _with ?? withParams?.searchV2
|
|
10
10
|
}
|
|
11
11
|
);
|
|
12
|
-
});
|
|
12
|
+
}, { method: "GET" });
|
|
13
13
|
export const resolveSearch = defineRpcHandler(async ({ term, with: _with, categoryId }, context) => {
|
|
14
14
|
const { cached, sapiClient, withParams } = context;
|
|
15
15
|
const resolvedEntity = await cached(sapiClient.searchv2.resolve, {
|
|
@@ -22,4 +22,4 @@ export const resolveSearch = defineRpcHandler(async ({ term, with: _with, catego
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
return resolvedEntity;
|
|
25
|
-
});
|
|
25
|
+
}, { method: "GET" });
|
|
@@ -99,7 +99,7 @@ export const oauthLogin = defineRpcHandler(async (login, context) => {
|
|
|
99
99
|
"Login failed"
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
|
-
});
|
|
102
|
+
}, { method: "POST" });
|
|
103
103
|
export const oauthRegister = defineRpcHandler(async (register, context) => {
|
|
104
104
|
if (!hasSession(context)) {
|
|
105
105
|
return new ErrorResponse(
|
|
@@ -132,7 +132,7 @@ export const oauthRegister = defineRpcHandler(async (register, context) => {
|
|
|
132
132
|
"Register failed"
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
|
-
});
|
|
135
|
+
}, { method: "POST" });
|
|
136
136
|
export const oauthGuestLogin = defineRpcHandler(async (guest, context) => {
|
|
137
137
|
if (!hasSession(context)) {
|
|
138
138
|
return new ErrorResponse(
|
|
@@ -164,7 +164,7 @@ export const oauthGuestLogin = defineRpcHandler(async (guest, context) => {
|
|
|
164
164
|
"Guest login failed"
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
|
-
});
|
|
167
|
+
}, { method: "POST" });
|
|
168
168
|
export const refreshAccessToken = defineRpcHandler(async (context) => {
|
|
169
169
|
if (!hasSession(context)) {
|
|
170
170
|
return new ErrorResponse(
|
|
@@ -212,7 +212,7 @@ export const refreshAccessToken = defineRpcHandler(async (context) => {
|
|
|
212
212
|
}
|
|
213
213
|
return { success: false };
|
|
214
214
|
}
|
|
215
|
-
});
|
|
215
|
+
}, { method: "POST" });
|
|
216
216
|
export const oauthRevokeToken = defineRpcHandler(async (context) => {
|
|
217
217
|
if (!hasSession(context)) {
|
|
218
218
|
return new ErrorResponse(
|
|
@@ -251,7 +251,7 @@ export const oauthRevokeToken = defineRpcHandler(async (context) => {
|
|
|
251
251
|
}
|
|
252
252
|
return { result: false };
|
|
253
253
|
}
|
|
254
|
-
});
|
|
254
|
+
}, { method: "POST" });
|
|
255
255
|
export const oauthForgetPassword = defineRpcHandler(async ({ email }, context) => {
|
|
256
256
|
if (!hasSession(context)) {
|
|
257
257
|
return new ErrorResponse(
|
|
@@ -294,7 +294,7 @@ export const oauthForgetPassword = defineRpcHandler(async ({ email }, context) =
|
|
|
294
294
|
}
|
|
295
295
|
return { success: false };
|
|
296
296
|
}
|
|
297
|
-
});
|
|
297
|
+
}, { method: "POST" });
|
|
298
298
|
export const updatePasswordByHash = defineRpcHandler(async (passwordHash, context) => {
|
|
299
299
|
if (!hasSession(context)) {
|
|
300
300
|
return new ErrorResponse(
|
|
@@ -331,4 +331,4 @@ export const updatePasswordByHash = defineRpcHandler(async (passwordHash, contex
|
|
|
331
331
|
);
|
|
332
332
|
}
|
|
333
333
|
return new Response(null, { status: HttpStatusCode.NO_CONTENT });
|
|
334
|
-
});
|
|
334
|
+
}, { method: "POST" });
|
|
@@ -17,7 +17,9 @@ const getUser = defineRpcHandler(
|
|
|
17
17
|
return {
|
|
18
18
|
user
|
|
19
19
|
};
|
|
20
|
-
}
|
|
20
|
+
},
|
|
21
|
+
// We use POST here to prevent user data to be leaking into caches.
|
|
22
|
+
{ method: "POST" }
|
|
21
23
|
);
|
|
22
24
|
const fetchUser = defineRpcHandler(async ({ accessToken }, context) => {
|
|
23
25
|
const { shopId } = context;
|
|
@@ -35,7 +37,7 @@ const fetchUser = defineRpcHandler(async ({ accessToken }, context) => {
|
|
|
35
37
|
({ shopId: shopId2 }) => shopId2 === context.shopId
|
|
36
38
|
);
|
|
37
39
|
return user;
|
|
38
|
-
});
|
|
40
|
+
}, { method: "POST" });
|
|
39
41
|
const refreshUser = defineRpcHandler(async (context) => {
|
|
40
42
|
if (!hasSession(context)) {
|
|
41
43
|
return new ErrorResponse(
|
|
@@ -59,7 +61,7 @@ const refreshUser = defineRpcHandler(async (context) => {
|
|
|
59
61
|
await context.destroySession();
|
|
60
62
|
return { user: void 0 };
|
|
61
63
|
}
|
|
62
|
-
});
|
|
64
|
+
}, { method: "POST" });
|
|
63
65
|
const getAccessToken = defineRpcHandler(async ({ forceTokenRefresh = false } = { forceTokenRefresh: false }, context) => {
|
|
64
66
|
if (!hasSession(context)) {
|
|
65
67
|
return new ErrorResponse(
|
|
@@ -107,5 +109,5 @@ const getAccessToken = defineRpcHandler(async ({ forceTokenRefresh = false } = {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
return context.accessToken;
|
|
110
|
-
});
|
|
112
|
+
}, { method: "POST" });
|
|
111
113
|
export { getUser, fetchUser, refreshUser, getAccessToken };
|
|
@@ -33,7 +33,8 @@ export const getWishlist = defineRpcHandler(
|
|
|
33
33
|
pricePromotionKey: pricePromotionKey ?? ""
|
|
34
34
|
}
|
|
35
35
|
);
|
|
36
|
-
}
|
|
36
|
+
},
|
|
37
|
+
{ method: "POST" }
|
|
37
38
|
);
|
|
38
39
|
export const addItemToWishlist = defineRpcHandler(async (options, context) => {
|
|
39
40
|
if (!hasSession(context)) {
|
|
@@ -46,7 +47,10 @@ export const addItemToWishlist = defineRpcHandler(async (options, context) => {
|
|
|
46
47
|
const { sapiClient, wishlistKey } = context;
|
|
47
48
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
48
49
|
const { productId, variantId } = options;
|
|
49
|
-
const { pricePromotionKey, ...resolvedWith } = getWithParams(
|
|
50
|
+
const { pricePromotionKey, ...resolvedWith } = getWithParams(
|
|
51
|
+
options,
|
|
52
|
+
context
|
|
53
|
+
);
|
|
50
54
|
if (!productId && !variantId) {
|
|
51
55
|
return new ErrorResponse(
|
|
52
56
|
HttpStatusCode.BAD_REQUEST,
|
|
@@ -70,7 +74,7 @@ export const addItemToWishlist = defineRpcHandler(async (options, context) => {
|
|
|
70
74
|
context.log.error("Adding to wishlist failed", result.wishlist);
|
|
71
75
|
return new Response(JSON.stringify({ kind, type }), { status: code });
|
|
72
76
|
}
|
|
73
|
-
});
|
|
77
|
+
}, { method: "PUT" });
|
|
74
78
|
export const removeItemFromWishlist = defineRpcHandler(async (options, context) => {
|
|
75
79
|
if (!hasSession(context)) {
|
|
76
80
|
return new ErrorResponse(
|
|
@@ -81,7 +85,10 @@ export const removeItemFromWishlist = defineRpcHandler(async (options, context)
|
|
|
81
85
|
}
|
|
82
86
|
const { sapiClient, wishlistKey } = context;
|
|
83
87
|
const campaignKey = await context.callRpc?.("getCampaignKey");
|
|
84
|
-
const { pricePromotionKey, ...resolvedWith } = getWithParams(
|
|
88
|
+
const { pricePromotionKey, ...resolvedWith } = getWithParams(
|
|
89
|
+
options,
|
|
90
|
+
context
|
|
91
|
+
);
|
|
85
92
|
return await mapSAPIFetchErrorToResponse(sapiClient.wishlist.deleteItem)(
|
|
86
93
|
wishlistKey,
|
|
87
94
|
options.itemKey,
|
|
@@ -91,7 +98,7 @@ export const removeItemFromWishlist = defineRpcHandler(async (options, context)
|
|
|
91
98
|
pricePromotionKey: pricePromotionKey ?? ""
|
|
92
99
|
}
|
|
93
100
|
);
|
|
94
|
-
});
|
|
101
|
+
}, { method: "DELETE" });
|
|
95
102
|
export const clearWishlist = defineRpcHandler(
|
|
96
103
|
async (context) => {
|
|
97
104
|
const wishlistResponse = await getWishlist({}, context);
|
|
@@ -105,5 +112,6 @@ export const clearWishlist = defineRpcHandler(
|
|
|
105
112
|
})
|
|
106
113
|
);
|
|
107
114
|
return await getWishlist({}, context);
|
|
108
|
-
}
|
|
115
|
+
},
|
|
116
|
+
{ method: "DELETE" }
|
|
109
117
|
);
|
package/dist/types/api/rpc.d.ts
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
import type { RpcContext } from './context';
|
|
2
|
+
/**
|
|
3
|
+
* Discriminator attached to RPC handlers indicating whether they accept a
|
|
4
|
+
* parameters argument or only the RPC context.
|
|
5
|
+
*/
|
|
6
|
+
export type RpcType = 'NoParam' | 'WithParam';
|
|
7
|
+
/**
|
|
8
|
+
* HTTP method an RPC handler is exposed under.
|
|
9
|
+
* `GET` is reserved for safe, idempotent, read-only calls (enables CDN/browser caching).
|
|
10
|
+
* `POST` is the default for every other call and for legacy handlers.
|
|
11
|
+
*/
|
|
12
|
+
export type RpcHttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
2
13
|
/**
|
|
3
14
|
* Type for an RPC handler that accepts parameters.
|
|
4
15
|
*
|
|
5
|
-
* @note In the upcoming major release `rpcType`
|
|
16
|
+
* @note In the upcoming major release the `rpcType` and `httpMethod` properties will be mandatory.
|
|
6
17
|
*
|
|
7
18
|
* @template Params The type of the parameters object.
|
|
8
19
|
* @template ResponseType The type of the response.
|
|
9
20
|
*/
|
|
10
21
|
export type ParamRpcHandler<Params extends Record<string, any>, ResponseType> = ((params: Params, context: RpcContext) => Promise<(ResponseType extends undefined ? void : ResponseType) | Response> | ResponseType | Response) & {
|
|
11
22
|
rpcType?: 'WithParam';
|
|
23
|
+
httpMethod?: RpcHttpMethod;
|
|
12
24
|
};
|
|
13
25
|
/**
|
|
14
26
|
* Type for an RPC handler that does not accept parameters.
|
|
15
27
|
*
|
|
16
|
-
* @note In the upcoming major release `rpcType`
|
|
28
|
+
* @note In the upcoming major release the `rpcType` and `httpMethod` properties will be mandatory.
|
|
17
29
|
*
|
|
18
30
|
* @template ResponseType The type of the response.
|
|
19
31
|
*/
|
|
20
32
|
export type NoParamRpcHandler<ResponseType> = ((context: RpcContext) => Promise<ResponseType | Response> | ResponseType | Response) & {
|
|
21
33
|
rpcType?: 'NoParam';
|
|
34
|
+
httpMethod?: RpcHttpMethod;
|
|
22
35
|
};
|
|
23
36
|
/**
|
|
24
37
|
* Generic RPC handler type. Handles both cases with and without parameters.
|
package/dist/utils/hash.mjs
CHANGED
|
@@ -35,10 +35,15 @@ export const hmac = async (value, secret, algorithm = "SHA-256") => {
|
|
|
35
35
|
};
|
|
36
36
|
function base64ToBytes(base64) {
|
|
37
37
|
const binString = atob(base64);
|
|
38
|
-
return Uint8Array.from(
|
|
38
|
+
return Uint8Array.from(
|
|
39
|
+
binString,
|
|
40
|
+
(m) => m.codePointAt(0)
|
|
41
|
+
);
|
|
39
42
|
}
|
|
40
43
|
function bytesToBase64(bytes) {
|
|
41
|
-
const binString = Array.from(bytes, (x) => String.fromCodePoint(x)).join(
|
|
44
|
+
const binString = Array.from(bytes, (x) => String.fromCodePoint(x)).join(
|
|
45
|
+
""
|
|
46
|
+
);
|
|
42
47
|
return btoa(binString);
|
|
43
48
|
}
|
|
44
49
|
export const encodeBase64 = (string) => {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export * from './basket';
|
|
|
5
5
|
export * from './campaign';
|
|
6
6
|
export { unwrap } from './response';
|
|
7
7
|
export { generateBasketKey, generateWishlistKey } from './keys';
|
|
8
|
-
export { defineRpcHandler } from './rpc';
|
|
8
|
+
export { defineRpcHandler, DEFAULT_RPC_HTTP_METHOD } from './rpc';
|
|
9
|
+
export type { DefineRpcHandlerOptions } from './rpc';
|
|
9
10
|
export { sha256 } from './hash';
|
package/dist/utils/index.mjs
CHANGED
|
@@ -5,5 +5,5 @@ export * from "./basket.mjs";
|
|
|
5
5
|
export * from "./campaign.mjs";
|
|
6
6
|
export { unwrap } from "./response.mjs";
|
|
7
7
|
export { generateBasketKey, generateWishlistKey } from "./keys.mjs";
|
|
8
|
-
export { defineRpcHandler } from "./rpc.mjs";
|
|
8
|
+
export { defineRpcHandler, DEFAULT_RPC_HTTP_METHOD } from "./rpc.mjs";
|
|
9
9
|
export { sha256 } from "./hash.mjs";
|
package/dist/utils/rpc.d.ts
CHANGED
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
import type { RpcMethods, RpcMethodName } from '..';
|
|
2
|
-
import type { RpcContext, RpcHandler } from '../types';
|
|
3
|
-
|
|
2
|
+
import type { RpcContext, RpcHandler, RpcHttpMethod, RpcType } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Options accepted by {@link defineRpcHandler}.
|
|
5
|
+
*/
|
|
6
|
+
export interface DefineRpcHandlerOptions {
|
|
7
|
+
/**
|
|
8
|
+
* HTTP method the RPC endpoint will be exposed under.
|
|
9
|
+
* Defaults to `'POST'`. Use `'GET'` for read-only, cacheable endpoints;
|
|
10
|
+
* `'PUT'` / `'DELETE'` for RESTful update/delete semantics.
|
|
11
|
+
*/
|
|
12
|
+
method?: RpcHttpMethod;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Default HTTP method for RPC handlers when not explicitly specified.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_RPC_HTTP_METHOD: RpcHttpMethod;
|
|
4
18
|
/**
|
|
5
19
|
* Defines an RPC method handler.
|
|
6
20
|
*
|
|
7
21
|
* @param handler - The RPC handler function.
|
|
22
|
+
* @param options - Optional handler options (e.g. HTTP method).
|
|
8
23
|
* @returns The handler itself, with correct types enforced and internal properties set.
|
|
9
24
|
*/
|
|
10
|
-
export declare function defineRpcHandler<Params extends Record<string, any> | undefined, Result>(handler: (params: Params, context: RpcContext) => Result | Response | Promise<Result | Response
|
|
25
|
+
export declare function defineRpcHandler<Params extends Record<string, any> | undefined, Result>(handler: (params: Params, context: RpcContext) => Result | Response | Promise<Result | Response>, options?: DefineRpcHandlerOptions): RpcHandler<Params, Result>;
|
|
11
26
|
/**
|
|
12
27
|
* Defines an RPC method handler.
|
|
13
28
|
*
|
|
14
29
|
* @param handler - The RPC handler function.
|
|
30
|
+
* @param options - Optional handler options (e.g. HTTP method).
|
|
15
31
|
* @returns The handler itself, with correct types enforced and internal properties set.
|
|
16
32
|
*/
|
|
17
|
-
export declare function defineRpcHandler<Result>(handler: (context: RpcContext) => Result | Response | Promise<Result | Response
|
|
33
|
+
export declare function defineRpcHandler<Result>(handler: (context: RpcContext) => Result | Response | Promise<Result | Response>, options?: DefineRpcHandlerOptions): RpcHandler<Result>;
|
|
18
34
|
/**
|
|
19
35
|
* Defines an RPC method handler.
|
|
20
36
|
*
|
|
21
37
|
* @param handler The RPC handler function.
|
|
38
|
+
* @param options Optional handler options (e.g. HTTP method).
|
|
22
39
|
* @returns The handler itself, with correct types enforced and internal properties set.
|
|
23
40
|
*/
|
|
24
|
-
export declare function defineRpcHandler<T extends RpcMethods[RpcMethodName]>(handler: T): T & {
|
|
41
|
+
export declare function defineRpcHandler<T extends RpcMethods[RpcMethodName]>(handler: T, options?: DefineRpcHandlerOptions): T & {
|
|
25
42
|
rpcType: RpcType;
|
|
43
|
+
httpMethod: RpcHttpMethod;
|
|
26
44
|
};
|
|
27
|
-
export {};
|
package/dist/utils/rpc.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const DEFAULT_RPC_HTTP_METHOD = "POST";
|
|
2
|
+
export function defineRpcHandler(handler, options) {
|
|
2
3
|
const rpcType = handler.length === 1 ? "NoParam" : "WithParam";
|
|
3
|
-
const
|
|
4
|
-
return
|
|
4
|
+
const httpMethod = options?.method ?? DEFAULT_RPC_HTTP_METHOD;
|
|
5
|
+
return Object.assign(handler, { rpcType, httpMethod });
|
|
5
6
|
}
|