@scayle/storefront-core 7.31.0 → 7.32.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,11 @@
1
1
  # @scayle/storefront-core
2
2
 
3
+ ## 7.32.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Use new password change API when oauth is enabled
8
+
3
9
  ## 7.31.0
4
10
 
5
11
  ### Minor Changes
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.OAuthClient = void 0;
7
+ exports.getOAuthClient = getOAuthClient;
7
8
  var _jose = require("jose");
8
9
  var _fetch = require("../utils/fetch.cjs");
9
10
  var _hash = require("../utils/hash.cjs");
@@ -25,10 +26,21 @@ function emptyOAuthResponseHandler(response) {
25
26
  throw new _fetch.FetchError(response);
26
27
  }
27
28
  }
29
+ function getOAuthClient(context) {
30
+ const clientId = context.oauth?.clientId;
31
+ const clientSecret = context.oauth?.clientSecret;
32
+ const apiHost = context.oauth?.apiHost;
33
+ return new OAuthClient({
34
+ clientId,
35
+ clientSecret,
36
+ apiHost
37
+ }, context.log);
38
+ }
28
39
  class OAuthClient {
29
40
  headers;
30
41
  baseURL;
31
- constructor(options) {
42
+ logger;
43
+ constructor(options, logger) {
32
44
  const {
33
45
  clientId,
34
46
  clientSecret,
@@ -38,6 +50,7 @@ class OAuthClient {
38
50
  throw new MissingCredentialsError();
39
51
  }
40
52
  this.baseURL = `${apiHost}/v1`;
53
+ this.logger = logger ? logger.space("auth-client") : void 0;
41
54
  const basicAuthHash = (0, _hash.encodeBase64)(`${clientId}:${clientSecret}`);
42
55
  this.headers = {
43
56
  Authorization: `Basic ${basicAuthHash}`,
@@ -50,6 +63,7 @@ class OAuthClient {
50
63
  * @param payload
51
64
  */
52
65
  async register(payload) {
66
+ this.logger?.debug("Registering user");
53
67
  return await fetch(`${this.baseURL}/auth/register`, {
54
68
  method: "POST",
55
69
  headers: this.headers,
@@ -61,6 +75,7 @@ class OAuthClient {
61
75
  * @param payload
62
76
  */
63
77
  async login(payload) {
78
+ this.logger?.debug("Logging in");
64
79
  return await fetch(`${this.baseURL}/auth/login`, {
65
80
  method: "POST",
66
81
  headers: this.headers,
@@ -72,6 +87,7 @@ class OAuthClient {
72
87
  * @param payload
73
88
  */
74
89
  async guestLogin(payload) {
90
+ this.logger?.debug("Logging in as guest");
75
91
  return await fetch(`${this.baseURL}/auth/login/guest`, {
76
92
  method: "POST",
77
93
  headers: this.headers,
@@ -83,6 +99,7 @@ class OAuthClient {
83
99
  * @param payload
84
100
  */
85
101
  async sendPasswordResetEmail(payload) {
102
+ this.logger?.debug("Sending password reset email");
86
103
  await fetch(`${this.baseURL}/auth/password/send-reset-email`, {
87
104
  method: "POST",
88
105
  headers: this.headers,
@@ -94,17 +111,35 @@ class OAuthClient {
94
111
  * @param payload
95
112
  */
96
113
  async updatePasswordByHash(payload) {
114
+ this.logger?.debug("Updating password by hash");
97
115
  return await fetch(`${this.baseURL}/auth/password/update-by-hash`, {
98
116
  method: "PUT",
99
117
  headers: this.headers,
100
118
  body: JSON.stringify(payload)
101
119
  }).then(oauthResponseHandler);
102
120
  }
121
+ /**
122
+ * Update a user's password
123
+ * @param payload
124
+ * @param accessToken
125
+ */
126
+ async updatePassword(payload, accessToken) {
127
+ this.logger?.debug("Updating password");
128
+ return await fetch(`${this.baseURL}/auth/password`, {
129
+ method: "PUT",
130
+ headers: {
131
+ ...this.headers,
132
+ Authorization: `Bearer ${accessToken}`
133
+ },
134
+ body: JSON.stringify(payload)
135
+ }).then(emptyOAuthResponseHandler);
136
+ }
103
137
  /**
104
138
  * Generate a new access token via a refresh token
105
139
  * @param payload
106
140
  */
107
141
  async refreshToken(payload) {
142
+ this.logger?.debug("Refreshing access token");
108
143
  return await fetch(`${this.baseURL}/oauth/token`, {
109
144
  method: "POST",
110
145
  headers: this.headers,
@@ -116,6 +151,7 @@ class OAuthClient {
116
151
  * @param accessToken
117
152
  */
118
153
  async validateToken(accessToken) {
154
+ this.logger?.debug("Validating access token");
119
155
  await fetch(`${this.baseURL}/oauth/token/validate`, {
120
156
  headers: {
121
157
  ...this.headers,
@@ -128,6 +164,7 @@ class OAuthClient {
128
164
  * @param accessToken
129
165
  */
130
166
  async revokeToken(accessToken) {
167
+ this.logger?.debug("Revoking access token");
131
168
  const decodedAccessToken = (0, _jose.decodeJwt)(accessToken);
132
169
  await fetch(`${this.baseURL}/oauth/tokens/${decodedAccessToken.jti}`, {
133
170
  method: "DELETE",
@@ -1,17 +1,21 @@
1
- import type { GuestRequest, LoginRequest, Oauth, RefreshTokenRequest, RegisterRequest, SendResetPasswordEmailRequest, UpdatePasswordByHashRequest } from '../types/api/auth';
1
+ import type { GuestRequest, LoginRequest, Oauth, RefreshTokenRequest, RegisterRequest, SendResetPasswordEmailRequest, UpdatePasswordByHashRequest, UpdatePasswordRequest } from '../types/api/auth';
2
+ import type { RpcContext } from '../types/api/context';
3
+ import type { Log } from '../utils/log';
2
4
  export interface OAuthOptions {
3
5
  clientId: string;
4
6
  clientSecret: string;
5
7
  apiHost: string;
6
8
  }
9
+ export declare function getOAuthClient(context: RpcContext): OAuthClient;
7
10
  /**
8
- * A client for interacting with the Checkout OAuth API
11
+ * A client for interacting with the Checkout Authentication API
9
12
  * Docs for all the routes: https://gitlab.com/aboutyou/checkout/schemas/checkout-auth-api/-/blob/main/build/openapi.yaml
10
13
  */
11
14
  export declare class OAuthClient {
12
15
  headers: HeadersInit;
13
16
  baseURL: string;
14
- constructor(options: OAuthOptions);
17
+ logger?: Log;
18
+ constructor(options: OAuthOptions, logger?: Log);
15
19
  /**
16
20
  * Register a user and retrieve a token set
17
21
  * @param payload
@@ -39,6 +43,12 @@ export declare class OAuthClient {
39
43
  * @param payload
40
44
  */
41
45
  updatePasswordByHash(payload: UpdatePasswordByHashRequest): Promise<Oauth>;
46
+ /**
47
+ * Update a user's password
48
+ * @param payload
49
+ * @param accessToken
50
+ */
51
+ updatePassword(payload: UpdatePasswordRequest, accessToken: string): Promise<void>;
42
52
  /**
43
53
  * Generate a new access token via a refresh token
44
54
  * @param payload
@@ -19,15 +19,23 @@ function emptyOAuthResponseHandler(response) {
19
19
  throw new FetchError(response);
20
20
  }
21
21
  }
22
+ export function getOAuthClient(context) {
23
+ const clientId = context.oauth?.clientId;
24
+ const clientSecret = context.oauth?.clientSecret;
25
+ const apiHost = context.oauth?.apiHost;
26
+ return new OAuthClient({ clientId, clientSecret, apiHost }, context.log);
27
+ }
22
28
  export class OAuthClient {
23
29
  headers;
24
30
  baseURL;
25
- constructor(options) {
31
+ logger;
32
+ constructor(options, logger) {
26
33
  const { clientId, clientSecret, apiHost } = options;
27
34
  if (!clientId || !clientSecret) {
28
35
  throw new MissingCredentialsError();
29
36
  }
30
37
  this.baseURL = `${apiHost}/v1`;
38
+ this.logger = logger ? logger.space("auth-client") : void 0;
31
39
  const basicAuthHash = encodeBase64(`${clientId}:${clientSecret}`);
32
40
  this.headers = {
33
41
  Authorization: `Basic ${basicAuthHash}`,
@@ -40,6 +48,7 @@ export class OAuthClient {
40
48
  * @param payload
41
49
  */
42
50
  async register(payload) {
51
+ this.logger?.debug("Registering user");
43
52
  return await fetch(`${this.baseURL}/auth/register`, {
44
53
  method: "POST",
45
54
  headers: this.headers,
@@ -51,6 +60,7 @@ export class OAuthClient {
51
60
  * @param payload
52
61
  */
53
62
  async login(payload) {
63
+ this.logger?.debug("Logging in");
54
64
  return await fetch(`${this.baseURL}/auth/login`, {
55
65
  method: "POST",
56
66
  headers: this.headers,
@@ -62,6 +72,7 @@ export class OAuthClient {
62
72
  * @param payload
63
73
  */
64
74
  async guestLogin(payload) {
75
+ this.logger?.debug("Logging in as guest");
65
76
  return await fetch(`${this.baseURL}/auth/login/guest`, {
66
77
  method: "POST",
67
78
  headers: this.headers,
@@ -73,6 +84,7 @@ export class OAuthClient {
73
84
  * @param payload
74
85
  */
75
86
  async sendPasswordResetEmail(payload) {
87
+ this.logger?.debug("Sending password reset email");
76
88
  await fetch(`${this.baseURL}/auth/password/send-reset-email`, {
77
89
  method: "POST",
78
90
  headers: this.headers,
@@ -84,17 +96,35 @@ export class OAuthClient {
84
96
  * @param payload
85
97
  */
86
98
  async updatePasswordByHash(payload) {
99
+ this.logger?.debug("Updating password by hash");
87
100
  return await fetch(`${this.baseURL}/auth/password/update-by-hash`, {
88
101
  method: "PUT",
89
102
  headers: this.headers,
90
103
  body: JSON.stringify(payload)
91
104
  }).then(oauthResponseHandler);
92
105
  }
106
+ /**
107
+ * Update a user's password
108
+ * @param payload
109
+ * @param accessToken
110
+ */
111
+ async updatePassword(payload, accessToken) {
112
+ this.logger?.debug("Updating password");
113
+ return await fetch(`${this.baseURL}/auth/password`, {
114
+ method: "PUT",
115
+ headers: {
116
+ ...this.headers,
117
+ Authorization: `Bearer ${accessToken}`
118
+ },
119
+ body: JSON.stringify(payload)
120
+ }).then(emptyOAuthResponseHandler);
121
+ }
93
122
  /**
94
123
  * Generate a new access token via a refresh token
95
124
  * @param payload
96
125
  */
97
126
  async refreshToken(payload) {
127
+ this.logger?.debug("Refreshing access token");
98
128
  return await fetch(`${this.baseURL}/oauth/token`, {
99
129
  method: "POST",
100
130
  headers: this.headers,
@@ -106,6 +136,7 @@ export class OAuthClient {
106
136
  * @param accessToken
107
137
  */
108
138
  async validateToken(accessToken) {
139
+ this.logger?.debug("Validating access token");
109
140
  await fetch(`${this.baseURL}/oauth/token/validate`, {
110
141
  headers: {
111
142
  ...this.headers,
@@ -118,6 +149,7 @@ export class OAuthClient {
118
149
  * @param accessToken
119
150
  */
120
151
  async revokeToken(accessToken) {
152
+ this.logger?.debug("Revoking access token");
121
153
  const decodedAccessToken = decodeJwt(accessToken);
122
154
  await fetch(`${this.baseURL}/oauth/tokens/${decodedAccessToken.jti}`, {
123
155
  method: "DELETE",
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.updateShopUser = exports.updatePassword = void 0;
7
7
  var _customer = require("../../../api/customer.cjs");
8
+ var _oauth = require("../../../api/oauth.cjs");
8
9
  var _fetch = require("../../../utils/fetch.cjs");
9
10
  var _httpStatus = require("../../../constants/httpStatus.cjs");
10
11
  const updateShopUser = exports.updateShopUser = async function updateShopUser2(payload, context) {
@@ -62,14 +63,25 @@ const updatePassword = exports.updatePassword = async function updatePassword2({
62
63
  newPassword
63
64
  }, context) {
64
65
  const shopUser = context.user;
65
- const client = new _customer.CustomerAPIClient({
66
- accessToken: context.accessToken,
67
- refreshToken: context.refreshToken,
68
- accessHeader: context.checkout.accessHeader,
69
- baseUrl: context.checkout.url
70
- });
66
+ const oauthEnabled = context.oauth.apiHost && context.oauth.clientId && context.oauth.clientSecret;
71
67
  try {
72
- const user = client.updatePassword(context.shopId, {
68
+ if (oauthEnabled) {
69
+ const client2 = (0, _oauth.getOAuthClient)(context);
70
+ await client2.updatePassword({
71
+ password: oldPassword,
72
+ new_password: newPassword
73
+ }, context.accessToken);
74
+ return {
75
+ user: shopUser
76
+ };
77
+ }
78
+ const client = new _customer.CustomerAPIClient({
79
+ accessToken: context.accessToken,
80
+ refreshToken: context.refreshToken,
81
+ accessHeader: context.checkout.accessHeader,
82
+ baseUrl: context.checkout.url
83
+ });
84
+ const user = await client.updatePassword(context.shopId, {
73
85
  password: oldPassword,
74
86
  newPassword
75
87
  });
@@ -1,4 +1,5 @@
1
1
  import { CustomerAPIClient } from "../../../api/customer.mjs";
2
+ import { getOAuthClient } from "../../../api/oauth.mjs";
2
3
  import { FetchError } from "../../../utils/fetch.mjs";
3
4
  import { HttpStatusCode } from "../../../constants/httpStatus.mjs";
4
5
  export const updateShopUser = async function updateShopUser2(payload, context) {
@@ -50,14 +51,26 @@ export const updateShopUser = async function updateShopUser2(payload, context) {
50
51
  };
51
52
  export const updatePassword = async function updatePassword2({ oldPassword, newPassword }, context) {
52
53
  const shopUser = context.user;
53
- const client = new CustomerAPIClient({
54
- accessToken: context.accessToken,
55
- refreshToken: context.refreshToken,
56
- accessHeader: context.checkout.accessHeader,
57
- baseUrl: context.checkout.url
58
- });
54
+ const oauthEnabled = context.oauth.apiHost && context.oauth.clientId && context.oauth.clientSecret;
59
55
  try {
60
- const user = client.updatePassword(context.shopId, {
56
+ if (oauthEnabled) {
57
+ const client2 = getOAuthClient(context);
58
+ await client2.updatePassword(
59
+ {
60
+ password: oldPassword,
61
+ new_password: newPassword
62
+ },
63
+ context.accessToken
64
+ );
65
+ return { user: shopUser };
66
+ }
67
+ const client = new CustomerAPIClient({
68
+ accessToken: context.accessToken,
69
+ refreshToken: context.refreshToken,
70
+ accessHeader: context.checkout.accessHeader,
71
+ baseUrl: context.checkout.url
72
+ });
73
+ const user = await client.updatePassword(context.shopId, {
61
74
  password: oldPassword,
62
75
  newPassword
63
76
  });
@@ -16,16 +16,6 @@ const convertErrorForRpcCall = (error, httpStatuses) => {
16
16
  }
17
17
  };
18
18
  exports.convertErrorForRpcCall = convertErrorForRpcCall;
19
- function getOAuthClient(context) {
20
- const clientId = context.oauth?.clientId ?? process.env.OAUTH_CLIENT_ID;
21
- const clientSecret = context.oauth?.clientSecret ?? process.env.OAUTH_CLIENT_SECRET;
22
- const apiHost = context.oauth?.apiHost ?? process.env.OAUTH_API_HOST;
23
- return new _oauth.OAuthClient({
24
- clientId,
25
- clientSecret,
26
- apiHost
27
- });
28
- }
29
19
  const saveUserOnSession = async (accessToken, context) => {
30
20
  const user = await (0, _user2.fetchUser)({
31
21
  accessToken,
@@ -47,7 +37,7 @@ async function postLogin(context, tokens) {
47
37
  }
48
38
  const oauthLogin = async (login, context) => {
49
39
  const shopId = context.shopId;
50
- const client = getOAuthClient(context);
40
+ const client = (0, _oauth.getOAuthClient)(context);
51
41
  if (!login.email || !login.password) {
52
42
  throw new Error("Login or password are missing, seems like validation has failed");
53
43
  }
@@ -67,7 +57,7 @@ const oauthLogin = async (login, context) => {
67
57
  exports.oauthLogin = oauthLogin;
68
58
  const oauthRegister = async (register, context) => {
69
59
  const shopId = context.shopId;
70
- const client = getOAuthClient(context);
60
+ const client = (0, _oauth.getOAuthClient)(context);
71
61
  try {
72
62
  const tokens = await client.register({
73
63
  ...register,
@@ -84,7 +74,7 @@ const oauthRegister = async (register, context) => {
84
74
  exports.oauthRegister = oauthRegister;
85
75
  const oauthGuestLogin = async (guest, context) => {
86
76
  const shopId = context.shopId;
87
- const client = getOAuthClient(context);
77
+ const client = (0, _oauth.getOAuthClient)(context);
88
78
  try {
89
79
  const tokens = client.guestLogin({
90
80
  ...guest,
@@ -101,7 +91,7 @@ const oauthGuestLogin = async (guest, context) => {
101
91
  exports.oauthGuestLogin = oauthGuestLogin;
102
92
  const refreshAccessToken = async context => {
103
93
  const refreshToken = context.refreshToken;
104
- const client = getOAuthClient(context);
94
+ const client = (0, _oauth.getOAuthClient)(context);
105
95
  if (!refreshToken) {
106
96
  throw new Error("No app refresh token provided");
107
97
  }
@@ -130,7 +120,7 @@ const oauthRevokeToken = async context => {
130
120
  if (!accessToken) {
131
121
  throw new Error("No app oauth authentication credentials");
132
122
  }
133
- const client = getOAuthClient(context);
123
+ const client = (0, _oauth.getOAuthClient)(context);
134
124
  await context.destroySession();
135
125
  try {
136
126
  await client.revokeToken(accessToken);
@@ -152,7 +142,7 @@ const oauthForgetPassword = async ({
152
142
  email
153
143
  }, context) => {
154
144
  const shopId = context.shopId;
155
- const client = getOAuthClient(context);
145
+ const client = (0, _oauth.getOAuthClient)(context);
156
146
  try {
157
147
  const resetUrl = new URL(context.auth.resetPasswordUrl);
158
148
  if (!resetUrl.searchParams.has("hash")) {
@@ -181,7 +171,7 @@ const oauthForgetPassword = async ({
181
171
  exports.oauthForgetPassword = oauthForgetPassword;
182
172
  const updatePasswordByHash = async (passwordHash, context) => {
183
173
  const shopId = context.shopId;
184
- const client = getOAuthClient(context);
174
+ const client = (0, _oauth.getOAuthClient)(context);
185
175
  try {
186
176
  const tokens = await client.updatePasswordByHash({
187
177
  ...passwordHash,
@@ -3,18 +3,12 @@ import { DEFAULT_WITH_LISTING, HttpStatusCode } from "../../constants/index.mjs"
3
3
  import { FetchError } from "../../utils/fetch.mjs";
4
4
  import { mergeBaskets, mergeWishlists } from "../../utils/user.mjs";
5
5
  import { fetchUser } from "../../rpc/methods/user.mjs";
6
- import { OAuthClient } from "../../api/oauth.mjs";
6
+ import { getOAuthClient } from "../../api/oauth.mjs";
7
7
  export const convertErrorForRpcCall = (error, httpStatuses) => {
8
8
  if (error instanceof FetchError && httpStatuses.includes(error.response.status)) {
9
9
  return error;
10
10
  }
11
11
  };
12
- function getOAuthClient(context) {
13
- const clientId = context.oauth?.clientId ?? process.env.OAUTH_CLIENT_ID;
14
- const clientSecret = context.oauth?.clientSecret ?? process.env.OAUTH_CLIENT_SECRET;
15
- const apiHost = context.oauth?.apiHost ?? process.env.OAUTH_API_HOST;
16
- return new OAuthClient({ clientId, clientSecret, apiHost });
17
- }
18
12
  const saveUserOnSession = async (accessToken, context) => {
19
13
  const user = await fetchUser({ accessToken, callback: "" }, context);
20
14
  context.updateUser(user);
@@ -55,6 +55,10 @@ export interface UpdatePasswordByHashRequest {
55
55
  hash: string;
56
56
  shop_id: number;
57
57
  }
58
+ export interface UpdatePasswordRequest {
59
+ password: string;
60
+ new_password: string;
61
+ }
58
62
  export interface RefreshTokenRequest {
59
63
  grant_type: 'refresh_token';
60
64
  refresh_token: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-core",
3
- "version": "7.31.0",
3
+ "version": "7.32.0",
4
4
  "description": "Collection of essential utilities to work with the Storefront API",
5
5
  "author": "SCAYLE Commerce Engine",
6
6
  "license": "MIT",
@@ -70,10 +70,10 @@
70
70
  "@scayle/prettier-config-storefront": "2.0.2",
71
71
  "@types/crypto-js": "4.2.1",
72
72
  "@types/jest": "29.5.11",
73
- "@types/node": "20.10.4",
73
+ "@types/node": "20.10.5",
74
74
  "@types/webpack-env": "1.18.4",
75
75
  "unbuild": "2.0.0",
76
- "eslint": "8.55.0",
76
+ "eslint": "8.56.0",
77
77
  "eslint-formatter-gitlab": "5.1.0",
78
78
  "jest": "29.7.0",
79
79
  "jest-junit": "16.0.0",