@scayle/storefront-core 8.61.1 → 8.61.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG-V7.md +1 -11
  2. package/CHANGELOG.md +96 -103
  3. package/dist/api/customer.mjs +1 -3
  4. package/dist/api/oauth.mjs +9 -6
  5. package/dist/cache/providers/unstorage.mjs +1 -3
  6. package/dist/constants/withParameters.mjs +2 -16
  7. package/dist/helpers/attributeHelpers.mjs +3 -1
  8. package/dist/helpers/filterHelper.mjs +11 -8
  9. package/dist/helpers/productHelpers.mjs +1 -3
  10. package/dist/helpers/sanitizationHelpers.mjs +1 -4
  11. package/dist/helpers/sortingHelper.mjs +1 -3
  12. package/dist/rpc/methods/basket/basket.d.ts +2 -2
  13. package/dist/rpc/methods/basket/basket.mjs +334 -321
  14. package/dist/rpc/methods/brands.mjs +26 -20
  15. package/dist/rpc/methods/campaign.mjs +32 -23
  16. package/dist/rpc/methods/categories.mjs +156 -135
  17. package/dist/rpc/methods/cbd.mjs +52 -49
  18. package/dist/rpc/methods/checkout/checkout.mjs +42 -39
  19. package/dist/rpc/methods/checkout/order.mjs +46 -40
  20. package/dist/rpc/methods/checkout/shopUser.mjs +112 -106
  21. package/dist/rpc/methods/navigationTrees.mjs +50 -32
  22. package/dist/rpc/methods/oauth/idp.mjs +64 -55
  23. package/dist/rpc/methods/products.mjs +224 -212
  24. package/dist/rpc/methods/promotion.mjs +46 -31
  25. package/dist/rpc/methods/search.mjs +26 -20
  26. package/dist/rpc/methods/session.mjs +289 -260
  27. package/dist/rpc/methods/shopConfiguration.mjs +12 -9
  28. package/dist/rpc/methods/user.mjs +87 -78
  29. package/dist/rpc/methods/variants.mjs +17 -14
  30. package/dist/rpc/methods/wishlist.mjs +71 -62
  31. package/dist/utils/hash.mjs +2 -7
  32. package/dist/utils/sapi.mjs +10 -7
  33. package/package.json +1 -1
@@ -6,51 +6,57 @@ import {
6
6
  HttpStatusMessage
7
7
  } from "../../../constants/httpStatus.mjs";
8
8
  import { defineRpcHandler } from "../../../utils/index.mjs";
9
- export const getOrderById = defineRpcHandler(async ({ orderId }, context) => {
10
- const accessToken = context.accessToken;
11
- if (!orderId || isNaN(orderId)) {
12
- return new ErrorResponse(
13
- HttpStatusCode.NOT_FOUND,
14
- HttpStatusMessage.NOT_FOUND,
15
- "No order ID provided"
16
- );
17
- }
18
- if (!accessToken) {
19
- return new ErrorResponse(
20
- HttpStatusCode.UNAUTHORIZED,
21
- HttpStatusMessage.UNAUTHORIZED,
22
- "No access token present"
23
- );
24
- }
25
- const client = new CustomerAPIClient(context);
26
- try {
27
- return await client.getOrder(context.shopId, orderId);
28
- } catch (error) {
29
- if (error instanceof FetchError) {
30
- if (error.response.status === HttpStatusCode.NOT_FOUND) {
9
+ export const getOrderById = defineRpcHandler(
10
+ async ({ orderId }, context) => {
11
+ const accessToken = context.accessToken;
12
+ if (!orderId || isNaN(orderId)) {
13
+ return new ErrorResponse(
14
+ HttpStatusCode.NOT_FOUND,
15
+ HttpStatusMessage.NOT_FOUND,
16
+ "No order ID provided"
17
+ );
18
+ }
19
+ if (!accessToken) {
20
+ return new ErrorResponse(
21
+ HttpStatusCode.UNAUTHORIZED,
22
+ HttpStatusMessage.UNAUTHORIZED,
23
+ "No access token present"
24
+ );
25
+ }
26
+ const client = new CustomerAPIClient(context);
27
+ try {
28
+ return await client.getOrder(context.shopId, orderId);
29
+ } catch (error) {
30
+ if (error instanceof FetchError) {
31
+ if (error.response.status === HttpStatusCode.NOT_FOUND) {
32
+ return new ErrorResponse(
33
+ HttpStatusCode.NOT_FOUND,
34
+ HttpStatusMessage.NOT_FOUND,
35
+ "Order not found"
36
+ );
37
+ }
31
38
  return new ErrorResponse(
32
- HttpStatusCode.NOT_FOUND,
33
- HttpStatusMessage.NOT_FOUND,
34
- "Order not found"
39
+ HttpStatusCode.INTERNAL_SERVER_ERROR,
40
+ HttpStatusMessage.INTERNAL_SERVER_ERROR,
41
+ "Unknown error",
42
+ {
43
+ detail: `Fetching order "${orderId}" failed with status code ${error.response.status}`
44
+ }
35
45
  );
36
46
  }
47
+ context.log.error("Error while fetching order details", { error });
37
48
  return new ErrorResponse(
38
49
  HttpStatusCode.INTERNAL_SERVER_ERROR,
39
50
  HttpStatusMessage.INTERNAL_SERVER_ERROR,
40
- "Unknown error",
41
- {
42
- detail: `Fetching order "${orderId}" failed with status code ${error.response.status}`
43
- }
51
+ "Unknown error"
44
52
  );
45
53
  }
46
- context.log.error("Error while fetching order details", { error });
47
- return new ErrorResponse(
48
- HttpStatusCode.INTERNAL_SERVER_ERROR,
49
- HttpStatusMessage.INTERNAL_SERVER_ERROR,
50
- "Unknown error"
51
- );
52
- }
53
- }, { method: "POST" });
54
- export const getOrderCustomData = defineRpcHandler(async () => {
55
- return {};
56
- }, { method: "POST" });
54
+ },
55
+ { method: "POST" }
56
+ );
57
+ export const getOrderCustomData = defineRpcHandler(
58
+ async () => {
59
+ return {};
60
+ },
61
+ { method: "POST" }
62
+ );
@@ -7,118 +7,124 @@ import {
7
7
  HttpStatusMessage
8
8
  } from "../../../constants/httpStatus.mjs";
9
9
  import { defineRpcHandler } from "../../../utils/index.mjs";
10
- export const updateShopUser = defineRpcHandler(async (payload, context) => {
11
- const shopId = context.shopId;
12
- const updatedUser = {
13
- email: payload.email,
14
- phone: payload.phone,
15
- firstName: payload.firstName,
16
- lastName: payload.lastName,
17
- birthDate: payload.birthDate,
18
- gender: payload.gender,
19
- title: payload.title
20
- };
21
- if (!context.user) {
22
- const message = "Unauthorized request: Missing access token";
23
- context.log.error(message);
24
- return new ErrorResponse(
25
- HttpStatusCode.UNAUTHORIZED,
26
- HttpStatusMessage.UNAUTHORIZED,
27
- "No access token present"
28
- );
29
- }
30
- const user = {
31
- ...context.user,
32
- ...updatedUser
33
- };
34
- const client = new CustomerAPIClient(context);
35
- try {
36
- await Promise.all([
37
- client.updateContactInfo(shopId, {
38
- email: user.email,
39
- phone: user.phone
40
- }),
41
- client.updatePersonalInfo(shopId, {
42
- firstName: user?.firstName,
43
- lastName: user?.lastName,
44
- birthDate: user?.birthDate,
45
- ...user?.gender && { gender: user?.gender },
46
- ...user?.title && { title: user?.title }
47
- })
48
- ]);
49
- context.updateUser(user);
50
- return { user };
51
- } catch (error) {
52
- context.log.error("Error while updating user information", error);
53
- return new ErrorResponse(
54
- HttpStatusCode.INTERNAL_SERVER_ERROR,
55
- HttpStatusMessage.INTERNAL_SERVER_ERROR,
56
- "Error while updating user information"
57
- );
58
- }
59
- }, { method: "PUT" });
60
- export const updatePassword = defineRpcHandler(async ({ oldPassword, newPassword }, context) => {
61
- const shopUser = context.user;
62
- const oauthEnabled = context.oauth?.apiHost && context.oauth?.clientId && context.oauth?.clientSecret;
63
- try {
64
- if (oauthEnabled) {
65
- const client2 = getOAuthClient(context);
66
- if (!context.accessToken) {
67
- return new ErrorResponse(
68
- HttpStatusCode.UNAUTHORIZED,
69
- HttpStatusMessage.UNAUTHORIZED,
70
- "No access token present"
71
- );
72
- }
73
- await client2.updatePassword(
74
- {
75
- password: oldPassword,
76
- new_password: newPassword
77
- },
78
- context.accessToken
10
+ export const updateShopUser = defineRpcHandler(
11
+ async (payload, context) => {
12
+ const shopId = context.shopId;
13
+ const updatedUser = {
14
+ email: payload.email,
15
+ phone: payload.phone,
16
+ firstName: payload.firstName,
17
+ lastName: payload.lastName,
18
+ birthDate: payload.birthDate,
19
+ gender: payload.gender,
20
+ title: payload.title
21
+ };
22
+ if (!context.user) {
23
+ const message = "Unauthorized request: Missing access token";
24
+ context.log.error(message);
25
+ return new ErrorResponse(
26
+ HttpStatusCode.UNAUTHORIZED,
27
+ HttpStatusMessage.UNAUTHORIZED,
28
+ "No access token present"
79
29
  );
80
- return { user: shopUser };
81
30
  }
31
+ const user = {
32
+ ...context.user,
33
+ ...updatedUser
34
+ };
82
35
  const client = new CustomerAPIClient(context);
83
- const user = await client.updatePassword(context.shopId, {
84
- password: oldPassword,
85
- newPassword
86
- });
87
- if (shopUser?.id) {
88
- await context.destroySessionsForUserId(shopUser.id, [context.sessionId]);
89
- }
90
- return { user };
91
- } catch (error) {
92
- if (!(error instanceof FetchError)) {
93
- context.log.error("Error while updating user's password", error);
36
+ try {
37
+ await Promise.all([
38
+ client.updateContactInfo(shopId, {
39
+ email: user.email,
40
+ phone: user.phone
41
+ }),
42
+ client.updatePersonalInfo(shopId, {
43
+ firstName: user?.firstName,
44
+ lastName: user?.lastName,
45
+ birthDate: user?.birthDate,
46
+ ...user?.gender && { gender: user?.gender },
47
+ ...user?.title && { title: user?.title }
48
+ })
49
+ ]);
50
+ context.updateUser(user);
51
+ return { user };
52
+ } catch (error) {
53
+ context.log.error("Error while updating user information", error);
94
54
  return new ErrorResponse(
95
55
  HttpStatusCode.INTERNAL_SERVER_ERROR,
96
56
  HttpStatusMessage.INTERNAL_SERVER_ERROR,
97
- "Error while updating user's password"
57
+ "Error while updating user information"
98
58
  );
99
59
  }
100
- if (error.response.status === HttpStatusCode.UNAUTHORIZED) {
101
- return new ErrorResponse(
102
- HttpStatusCode.UNAUTHORIZED,
103
- HttpStatusMessage.UNAUTHORIZED,
104
- "Failed to update user's password",
105
- { detail: "Unauthorized request" }
106
- );
107
- } else if (error.response.status === HttpStatusCode.FORBIDDEN) {
108
- return new ErrorResponse(
109
- HttpStatusCode.FORBIDDEN,
110
- HttpStatusMessage.FORBIDDEN,
111
- "Failed to update user's password",
112
- { detail: "Invalid auth" }
113
- );
114
- } else if (error.response.status === HttpStatusCode.NOT_FOUND) {
115
- return new ErrorResponse(
116
- HttpStatusCode.NOT_FOUND,
117
- HttpStatusMessage.NOT_FOUND,
118
- "Failed to update user's password",
119
- { detail: "User not found" }
120
- );
60
+ },
61
+ { method: "PUT" }
62
+ );
63
+ export const updatePassword = defineRpcHandler(
64
+ async ({ oldPassword, newPassword }, context) => {
65
+ const shopUser = context.user;
66
+ const oauthEnabled = context.oauth?.apiHost && context.oauth?.clientId && context.oauth?.clientSecret;
67
+ try {
68
+ if (oauthEnabled) {
69
+ const client2 = getOAuthClient(context);
70
+ if (!context.accessToken) {
71
+ return new ErrorResponse(
72
+ HttpStatusCode.UNAUTHORIZED,
73
+ HttpStatusMessage.UNAUTHORIZED,
74
+ "No access token present"
75
+ );
76
+ }
77
+ await client2.updatePassword(
78
+ {
79
+ password: oldPassword,
80
+ new_password: newPassword
81
+ },
82
+ context.accessToken
83
+ );
84
+ return { user: shopUser };
85
+ }
86
+ const client = new CustomerAPIClient(context);
87
+ const user = await client.updatePassword(context.shopId, {
88
+ password: oldPassword,
89
+ newPassword
90
+ });
91
+ if (shopUser?.id) {
92
+ await context.destroySessionsForUserId(shopUser.id, [context.sessionId]);
93
+ }
94
+ return { user };
95
+ } catch (error) {
96
+ if (!(error instanceof FetchError)) {
97
+ context.log.error("Error while updating user's password", error);
98
+ return new ErrorResponse(
99
+ HttpStatusCode.INTERNAL_SERVER_ERROR,
100
+ HttpStatusMessage.INTERNAL_SERVER_ERROR,
101
+ "Error while updating user's password"
102
+ );
103
+ }
104
+ if (error.response.status === HttpStatusCode.UNAUTHORIZED) {
105
+ return new ErrorResponse(
106
+ HttpStatusCode.UNAUTHORIZED,
107
+ HttpStatusMessage.UNAUTHORIZED,
108
+ "Failed to update user's password",
109
+ { detail: "Unauthorized request" }
110
+ );
111
+ } else if (error.response.status === HttpStatusCode.FORBIDDEN) {
112
+ return new ErrorResponse(
113
+ HttpStatusCode.FORBIDDEN,
114
+ HttpStatusMessage.FORBIDDEN,
115
+ "Failed to update user's password",
116
+ { detail: "Invalid auth" }
117
+ );
118
+ } else if (error.response.status === HttpStatusCode.NOT_FOUND) {
119
+ return new ErrorResponse(
120
+ HttpStatusCode.NOT_FOUND,
121
+ HttpStatusMessage.NOT_FOUND,
122
+ "Failed to update user's password",
123
+ { detail: "User not found" }
124
+ );
125
+ }
121
126
  }
122
- }
123
- return { user: shopUser };
124
- }, { method: "PUT" });
127
+ return { user: shopUser };
128
+ },
129
+ { method: "PUT" }
130
+ );
@@ -1,37 +1,55 @@
1
1
  import { ErrorResponse } from "../../errors/index.mjs";
2
2
  import { HttpStatusCode, HttpStatusMessage } from "../../constants/index.mjs";
3
3
  import { defineRpcHandler } from "../../utils/index.mjs";
4
- export const fetchAllNavigationTrees = defineRpcHandler(async ({ params }, context) => {
5
- const { sapiClient: { navigation }, cached } = context;
6
- return await cached(navigation.getAll, {
7
- cacheKeyPrefix: "getAll-navigation-trees"
8
- })(params);
9
- }, { method: "GET" });
10
- export const fetchNavigationTreeById = defineRpcHandler(async ({ treeId, params }, context) => {
11
- const { sapiClient: { navigation }, cached } = context;
12
- return await cached(navigation.getById, {
13
- cacheKeyPrefix: `getById-navigation-trees-${treeId}`
14
- })(treeId, params);
15
- }, { method: "GET" });
16
- export const fetchNavigationTreeByName = defineRpcHandler(async ({ treeName, params }, context) => {
17
- const { sapiClient: { navigation }, cached } = context;
18
- return await cached(
19
- async (name, params2) => {
20
- const navigationTree = (await navigation.getAll(params2)).find(
21
- (nav) => nav.name === treeName
22
- );
23
- if (!navigationTree) {
24
- return new ErrorResponse(
25
- HttpStatusCode.NOT_FOUND,
26
- `No navigation tree with name "${treeName}" found.`,
27
- HttpStatusMessage.NOT_FOUND,
28
- { name }
4
+ export const fetchAllNavigationTrees = defineRpcHandler(
5
+ async ({ params }, context) => {
6
+ const {
7
+ sapiClient: { navigation },
8
+ cached
9
+ } = context;
10
+ return await cached(navigation.getAll, {
11
+ cacheKeyPrefix: "getAll-navigation-trees"
12
+ })(params);
13
+ },
14
+ { method: "GET" }
15
+ );
16
+ export const fetchNavigationTreeById = defineRpcHandler(
17
+ async ({ treeId, params }, context) => {
18
+ const {
19
+ sapiClient: { navigation },
20
+ cached
21
+ } = context;
22
+ return await cached(navigation.getById, {
23
+ cacheKeyPrefix: `getById-navigation-trees-${treeId}`
24
+ })(treeId, params);
25
+ },
26
+ { method: "GET" }
27
+ );
28
+ export const fetchNavigationTreeByName = defineRpcHandler(
29
+ async ({ treeName, params }, context) => {
30
+ const {
31
+ sapiClient: { navigation },
32
+ cached
33
+ } = context;
34
+ return await cached(
35
+ async (name, params2) => {
36
+ const navigationTree = (await navigation.getAll(params2)).find(
37
+ (nav) => nav.name === treeName
29
38
  );
39
+ if (!navigationTree) {
40
+ return new ErrorResponse(
41
+ HttpStatusCode.NOT_FOUND,
42
+ `No navigation tree with name "${treeName}" found.`,
43
+ HttpStatusMessage.NOT_FOUND,
44
+ { name }
45
+ );
46
+ }
47
+ return navigationTree;
48
+ },
49
+ {
50
+ cacheKeyPrefix: `getByName-navigation-trees-${treeName}`
30
51
  }
31
- return navigationTree;
32
- },
33
- {
34
- cacheKeyPrefix: `getByName-navigation-trees-${treeName}`
35
- }
36
- )(treeName, params);
37
- }, { method: "GET" });
52
+ )(treeName, params);
53
+ },
54
+ { method: "GET" }
55
+ );
@@ -5,60 +5,69 @@ import { hasSession } from "../../../types/index.mjs";
5
5
  import { getOAuthClient } from "../../../api/oauth.mjs";
6
6
  import { postLogin } from "../session.mjs";
7
7
  import { defineRpcHandler } from "../../../utils/index.mjs";
8
- export const getExternalIdpRedirect = defineRpcHandler(async ({ queryParams, authUrlParameters }, context) => {
9
- if (!context.idp?.enabled) {
10
- return {};
11
- }
12
- if (context.idp.idpKeys.length === 0) {
13
- return new ErrorResponse(
14
- HttpStatusCode.BAD_REQUEST,
15
- HttpStatusMessage.BAD_REQUEST,
16
- "No IDP keys are configured"
17
- );
18
- }
19
- if (!context.idp.idpRedirectURL) {
20
- return new ErrorResponse(
21
- HttpStatusCode.BAD_REQUEST,
22
- HttpStatusMessage.BAD_REQUEST,
23
- "No IDP redirect url is configured"
24
- );
25
- }
26
- const OAuthClient = getOAuthClient(context);
27
- const redirectUrl = new URL(context.idp.idpRedirectURL);
28
- if (queryParams) {
29
- for (const [key, value] of Object.entries(queryParams)) {
30
- redirectUrl.searchParams.set(key, value);
8
+ export const getExternalIdpRedirect = defineRpcHandler(
9
+ async ({
10
+ queryParams,
11
+ authUrlParameters
12
+ }, context) => {
13
+ if (!context.idp?.enabled) {
14
+ return {};
15
+ }
16
+ if (context.idp.idpKeys.length === 0) {
17
+ return new ErrorResponse(
18
+ HttpStatusCode.BAD_REQUEST,
19
+ HttpStatusMessage.BAD_REQUEST,
20
+ "No IDP keys are configured"
21
+ );
31
22
  }
32
- }
33
- const secret = new TextEncoder().encode(context.checkout.secret);
34
- const results = await Promise.all(
35
- context.idp.idpKeys.map(async (idpKey) => {
36
- const jwtPayload = await new SignJWT({
37
- idpKey,
38
- callbackUrl: redirectUrl.toString(),
39
- clientId: OAuthClient.clientId.toString(),
40
- authUrlParameters
41
- }).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setExpirationTime("2h").sign(secret);
42
- const url = new URL(`${OAuthClient.baseURL}/auth/external/redirect`);
43
- url.searchParams.set("shopId", `${context.shopId}`);
44
- url.searchParams.set("jwt", jwtPayload);
45
- return [idpKey, url.toString()];
46
- })
47
- );
48
- return Object.fromEntries(results);
49
- }, { method: "GET" });
50
- export const handleIDPLoginCallback = defineRpcHandler(async (payload, context) => {
51
- if (!hasSession(context)) {
52
- return new ErrorResponse(
53
- HttpStatusCode.BAD_REQUEST,
54
- HttpStatusMessage.BAD_REQUEST,
55
- "No Session found"
23
+ if (!context.idp.idpRedirectURL) {
24
+ return new ErrorResponse(
25
+ HttpStatusCode.BAD_REQUEST,
26
+ HttpStatusMessage.BAD_REQUEST,
27
+ "No IDP redirect url is configured"
28
+ );
29
+ }
30
+ const OAuthClient = getOAuthClient(context);
31
+ const redirectUrl = new URL(context.idp.idpRedirectURL);
32
+ if (queryParams) {
33
+ for (const [key, value] of Object.entries(queryParams)) {
34
+ redirectUrl.searchParams.set(key, value);
35
+ }
36
+ }
37
+ const secret = new TextEncoder().encode(context.checkout.secret);
38
+ const results = await Promise.all(
39
+ context.idp.idpKeys.map(async (idpKey) => {
40
+ const jwtPayload = await new SignJWT({
41
+ idpKey,
42
+ callbackUrl: redirectUrl.toString(),
43
+ clientId: OAuthClient.clientId.toString(),
44
+ authUrlParameters
45
+ }).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setExpirationTime("2h").sign(secret);
46
+ const url = new URL(`${OAuthClient.baseURL}/auth/external/redirect`);
47
+ url.searchParams.set("shopId", `${context.shopId}`);
48
+ url.searchParams.set("jwt", jwtPayload);
49
+ return [idpKey, url.toString()];
50
+ })
56
51
  );
57
- }
58
- const OAuthClient = getOAuthClient(context);
59
- const tokens = await OAuthClient.generateToken(payload.code);
60
- await postLogin(context, tokens);
61
- return {
62
- message: "success"
63
- };
64
- }, { method: "POST" });
52
+ return Object.fromEntries(results);
53
+ },
54
+ { method: "GET" }
55
+ );
56
+ export const handleIDPLoginCallback = defineRpcHandler(
57
+ async (payload, context) => {
58
+ if (!hasSession(context)) {
59
+ return new ErrorResponse(
60
+ HttpStatusCode.BAD_REQUEST,
61
+ HttpStatusMessage.BAD_REQUEST,
62
+ "No Session found"
63
+ );
64
+ }
65
+ const OAuthClient = getOAuthClient(context);
66
+ const tokens = await OAuthClient.generateToken(payload.code);
67
+ await postLogin(context, tokens);
68
+ return {
69
+ message: "success"
70
+ };
71
+ },
72
+ { method: "POST" }
73
+ );