@scayle/storefront-core 7.34.1 → 7.36.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,18 @@
1
1
  # @scayle/storefront-core
2
2
 
3
+ ## 7.36.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Support `Response` returns in RPC methods
8
+ - Handle 401 from CO and delete session
9
+
10
+ ## 7.35.0
11
+
12
+ ### Minor Changes
13
+
14
+ - Change `oauthForgetPassword` payload signature to accept `email` only
15
+
3
16
  ## 7.34.1
4
17
 
5
18
  ### Patch Changes
@@ -7,17 +7,16 @@ exports.CustomerAPIClient = void 0;
7
7
  var _fetch = require("../utils/fetch.cjs");
8
8
  var _httpStatus = require("../constants/httpStatus.cjs");
9
9
  class CustomerAPIClient {
10
- headers;
11
10
  baseURL;
12
- constructor(options) {
13
- const {
14
- accessToken,
15
- accessHeader,
16
- baseUrl
17
- } = options;
18
- this.baseURL = baseUrl;
19
- this.headers = {
20
- Authorization: `Bearer ${accessToken}`,
11
+ context;
12
+ constructor(context) {
13
+ this.baseURL = context.checkout.url;
14
+ this.context = context;
15
+ }
16
+ get headers() {
17
+ const accessHeader = this.context.checkout.accessHeader;
18
+ return {
19
+ Authorization: `Bearer ${this.context.accessToken}`,
21
20
  Accept: "application/json",
22
21
  "Content-Type": "application/json",
23
22
  ...(accessHeader ? {
@@ -27,6 +26,10 @@ class CustomerAPIClient {
27
26
  }
28
27
  async handleResponse(response) {
29
28
  if (!response.ok) {
29
+ if (response.status === _httpStatus.HttpStatusCode.UNAUTHORIZED && this.context.accessToken) {
30
+ this.context.log.debug("Invalid Checkout Token. Deleting session");
31
+ await this.context.destroySession();
32
+ }
30
33
  throw new _fetch.FetchError(response);
31
34
  }
32
35
  return await response.json();
@@ -1,19 +1,4 @@
1
- import type { ShopUserAddress, Order, ShopUser, Gender } from '../types';
2
- interface CustomerAPIOptions {
3
- /**
4
- * The OAuth Access Token
5
- */
6
- accessToken: string;
7
- /**
8
- * The OAuth Refresh Token
9
- */
10
- refreshToken: string;
11
- accessHeader: string;
12
- /**
13
- * The Checkout Host
14
- */
15
- baseUrl: string;
16
- }
1
+ import type { ShopUserAddress, Order, ShopUser, Gender, RpcContext } from '../types';
17
2
  interface PaginatedResponse<EntityType> {
18
3
  entities: EntityType[];
19
4
  pagination: {
@@ -50,9 +35,10 @@ interface PasswordUpdate {
50
35
  * @see https://scayle.dev/api/oauth/latest
51
36
  */
52
37
  export declare class CustomerAPIClient {
53
- headers: HeadersInit;
54
38
  baseURL: string;
55
- constructor(options: CustomerAPIOptions);
39
+ context: RpcContext;
40
+ constructor(context: RpcContext);
41
+ get headers(): HeadersInit;
56
42
  handleResponse<BodyType>(response: Response): Promise<BodyType>;
57
43
  /**
58
44
  * Get the addresses for the current customer
@@ -1,13 +1,16 @@
1
1
  import { FetchError } from "../utils/fetch.mjs";
2
2
  import { HttpStatusCode } from "../constants/httpStatus.mjs";
3
3
  export class CustomerAPIClient {
4
- headers;
5
4
  baseURL;
6
- constructor(options) {
7
- const { accessToken, accessHeader, baseUrl } = options;
8
- this.baseURL = baseUrl;
9
- this.headers = {
10
- Authorization: `Bearer ${accessToken}`,
5
+ context;
6
+ constructor(context) {
7
+ this.baseURL = context.checkout.url;
8
+ this.context = context;
9
+ }
10
+ get headers() {
11
+ const accessHeader = this.context.checkout.accessHeader;
12
+ return {
13
+ Authorization: `Bearer ${this.context.accessToken}`,
11
14
  Accept: "application/json",
12
15
  "Content-Type": "application/json",
13
16
  ...accessHeader ? { "X-Access-Header": accessHeader } : {}
@@ -15,6 +18,10 @@ export class CustomerAPIClient {
15
18
  }
16
19
  async handleResponse(response) {
17
20
  if (!response.ok) {
21
+ if (response.status === HttpStatusCode.UNAUTHORIZED && this.context.accessToken) {
22
+ this.context.log.debug("Invalid Checkout Token. Deleting session");
23
+ await this.context.destroySession();
24
+ }
18
25
  throw new FetchError(response);
19
26
  }
20
27
  return await response.json();
@@ -21,12 +21,7 @@ const getOrderById = exports.getOrderById = async function getOrderById2({
21
21
  if (!isOrderInUserOrderlist) {
22
22
  throw new Error("Order not belonging to current user");
23
23
  }
24
- const client = new _customer.CustomerAPIClient({
25
- accessToken: context.accessToken,
26
- refreshToken: context.refreshToken,
27
- accessHeader: context.checkout.accessHeader,
28
- baseUrl: context.checkout.url
29
- });
24
+ const client = new _customer.CustomerAPIClient(context);
30
25
  try {
31
26
  return await client.getOrder(context.shopId, orderId);
32
27
  } catch (error) {
@@ -15,12 +15,7 @@ export const getOrderById = async function getOrderById2({ orderId }, context) {
15
15
  if (!isOrderInUserOrderlist) {
16
16
  throw new Error("Order not belonging to current user");
17
17
  }
18
- const client = new CustomerAPIClient({
19
- accessToken: context.accessToken,
20
- refreshToken: context.refreshToken,
21
- accessHeader: context.checkout.accessHeader,
22
- baseUrl: context.checkout.url
23
- });
18
+ const client = new CustomerAPIClient(context);
24
19
  try {
25
20
  return await client.getOrder(context.shopId, orderId);
26
21
  } catch (error) {
@@ -28,12 +28,7 @@ const updateShopUser = exports.updateShopUser = async function updateShopUser2(p
28
28
  ...context.user,
29
29
  ...updatedUser
30
30
  };
31
- const client = new _customer.CustomerAPIClient({
32
- accessToken: context.accessToken,
33
- refreshToken: context.refreshToken,
34
- accessHeader: context.checkout.accessHeader,
35
- baseUrl: context.checkout.url
36
- });
31
+ const client = new _customer.CustomerAPIClient(context);
37
32
  try {
38
33
  await Promise.all([client.updateContactInfo(shopId, {
39
34
  email: user.email,
@@ -75,12 +70,7 @@ const updatePassword = exports.updatePassword = async function updatePassword2({
75
70
  user: shopUser
76
71
  };
77
72
  }
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
- });
73
+ const client = new _customer.CustomerAPIClient(context);
84
74
  const user = await client.updatePassword(context.shopId, {
85
75
  password: oldPassword,
86
76
  newPassword
@@ -22,12 +22,7 @@ export const updateShopUser = async function updateShopUser2(payload, context) {
22
22
  ...context.user,
23
23
  ...updatedUser
24
24
  };
25
- const client = new CustomerAPIClient({
26
- accessToken: context.accessToken,
27
- refreshToken: context.refreshToken,
28
- accessHeader: context.checkout.accessHeader,
29
- baseUrl: context.checkout.url
30
- });
25
+ const client = new CustomerAPIClient(context);
31
26
  try {
32
27
  await Promise.all([
33
28
  client.updateContactInfo(shopId, {
@@ -64,12 +59,7 @@ export const updatePassword = async function updatePassword2({ oldPassword, newP
64
59
  );
65
60
  return { user: shopUser };
66
61
  }
67
- const client = new CustomerAPIClient({
68
- accessToken: context.accessToken,
69
- refreshToken: context.refreshToken,
70
- accessHeader: context.checkout.accessHeader,
71
- baseUrl: context.checkout.url
72
- });
62
+ const client = new CustomerAPIClient(context);
73
63
  const user = await client.updatePassword(context.shopId, {
74
64
  password: oldPassword,
75
65
  newPassword
@@ -7,11 +7,6 @@ exports.getShopUserAddresses = void 0;
7
7
  var _customer = require("../../../api/customer.cjs");
8
8
  const getShopUserAddresses = exports.getShopUserAddresses = async function getShopUserAddresses2(context) {
9
9
  const shopId = context.shopId;
10
- const client = new _customer.CustomerAPIClient({
11
- accessToken: context.accessToken,
12
- refreshToken: context.refreshToken,
13
- accessHeader: context.checkout.accessHeader,
14
- baseUrl: context.checkout.url
15
- });
10
+ const client = new _customer.CustomerAPIClient(context);
16
11
  return (await client.getAddresses(shopId)).entities;
17
12
  };
@@ -1,12 +1,7 @@
1
1
  import { CustomerAPIClient } from "../../../api/customer.mjs";
2
2
  const getShopUserAddresses = async function getShopUserAddresses2(context) {
3
3
  const shopId = context.shopId;
4
- const client = new CustomerAPIClient({
5
- accessToken: context.accessToken,
6
- refreshToken: context.refreshToken,
7
- accessHeader: context.checkout.accessHeader,
8
- baseUrl: context.checkout.url
9
- });
4
+ const client = new CustomerAPIClient(context);
10
5
  return (await client.getAddresses(shopId)).entities;
11
6
  };
12
7
  export { getShopUserAddresses };
@@ -1,5 +1,5 @@
1
1
  import type { Optional } from 'utility-types';
2
- import type { GuestRequest, LoginRequest, ParamRpcHandler, RegisterRequest, RpcHandler, SendResetPasswordEmailRequest, UpdatePasswordByHashRequest } from '../../types';
2
+ import type { GuestRequest, LoginRequest, ParamRpcHandler, RegisterRequest, RpcHandler, UpdatePasswordByHashRequest } from '../../types';
3
3
  /**
4
4
  * Ensure error is a fetch error with one of the status codes
5
5
  */
@@ -13,7 +13,9 @@ export declare const refreshAccessToken: RpcHandler<{
13
13
  export declare const oauthRevokeToken: RpcHandler<{
14
14
  result: boolean;
15
15
  }>;
16
- export declare const oauthForgetPassword: RpcHandler<SendResetPasswordEmailRequest, {
16
+ export declare const oauthForgetPassword: RpcHandler<{
17
+ email: string;
18
+ }, {
17
19
  success: boolean;
18
20
  }>;
19
21
  export declare const updatePasswordByHash: ParamRpcHandler<Optional<UpdatePasswordByHashRequest, 'shop_id'>, undefined>;
@@ -17,12 +17,7 @@ const fetchUser = exports.fetchUser = async function fetchUser2(payload, context
17
17
  const {
18
18
  shopId
19
19
  } = context;
20
- const client = new _customer.CustomerAPIClient({
21
- accessToken: context.accessToken,
22
- refreshToken: context.refreshToken,
23
- accessHeader: context.checkout.accessHeader,
24
- baseUrl: context.checkout.url
25
- });
20
+ const client = new _customer.CustomerAPIClient(context);
26
21
  const user = await client.getMe(shopId);
27
22
  return {
28
23
  ...user,
@@ -40,12 +35,7 @@ const refreshUser = exports.refreshUser = async function refreshUser2(context) {
40
35
  accessToken,
41
36
  shopId
42
37
  } = context;
43
- const client = new _customer.CustomerAPIClient({
44
- accessToken: context.accessToken,
45
- refreshToken: context.refreshToken,
46
- accessHeader: context.checkout.accessHeader,
47
- baseUrl: context.checkout.url
48
- });
38
+ const client = new _customer.CustomerAPIClient(context);
49
39
  const user = await client.getMe(shopId);
50
40
  if (user?.id) {
51
41
  context.updateUser({
@@ -7,12 +7,7 @@ const getUser = function getUser2(context) {
7
7
  const fetchUser = async function fetchUser2(payload, context) {
8
8
  const { accessToken } = payload;
9
9
  const { shopId } = context;
10
- const client = new CustomerAPIClient({
11
- accessToken: context.accessToken,
12
- refreshToken: context.refreshToken,
13
- accessHeader: context.checkout.accessHeader,
14
- baseUrl: context.checkout.url
15
- });
10
+ const client = new CustomerAPIClient(context);
16
11
  const user = await client.getMe(shopId);
17
12
  return {
18
13
  ...user,
@@ -25,12 +20,7 @@ const fetchUser = async function fetchUser2(payload, context) {
25
20
  };
26
21
  const refreshUser = async function refreshUser2(context) {
27
22
  const { accessToken, shopId } = context;
28
- const client = new CustomerAPIClient({
29
- accessToken: context.accessToken,
30
- refreshToken: context.refreshToken,
31
- accessHeader: context.checkout.accessHeader,
32
- baseUrl: context.checkout.url
33
- });
23
+ const client = new CustomerAPIClient(context);
34
24
  const user = await client.getMe(shopId);
35
25
  if (user?.id) {
36
26
  context.updateUser({
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.removeItemFromWishlist = exports.getWishlist = exports.clearWishlist = exports.addItemToWishlist = void 0;
7
- var _errors = require("../../errors/index.cjs");
8
7
  var _constants = require("../../constants/index.cjs");
9
8
  function getWithParams(params, context) {
10
9
  return params.with ?? context.withParams?.basket ?? _constants.MIN_WITH_PARAMS_WISHLIST;
@@ -41,7 +40,11 @@ const addItemToWishlist = exports.addItemToWishlist = async function addItemToWi
41
40
  message
42
41
  } = result.wishlist;
43
42
  context.log.error("Adding to wishlist failed", result.wishlist);
44
- throw new _errors.BAPIError("BAPI ERROR", code, message, "bapiClient.wishlist.addItem");
43
+ return new Response(JSON.stringify({
44
+ message
45
+ }), {
46
+ status: code
47
+ });
45
48
  }
46
49
  };
47
50
  const getWishlist = exports.getWishlist = async function getWishlist2(options, context) {
@@ -1,10 +1,10 @@
1
1
  import type { WishlistResponseData } from '@aboutyou/backbone/endpoints/wishlist/getWishlist';
2
- import { RpcHandler, WishlistWithOptions } from '../../types';
3
- export declare const addItemToWishlist: RpcHandler<{
2
+ import { RpcHandler, ParamRpcHandler, WishlistWithOptions } from '../../types';
3
+ export declare const addItemToWishlist: ParamRpcHandler<{
4
4
  variantId?: number;
5
5
  productId?: number;
6
6
  with?: WishlistWithOptions;
7
- }, WishlistResponseData>;
7
+ }, WishlistResponseData | Response>;
8
8
  export declare const getWishlist: RpcHandler<WishlistWithOptions | undefined, WishlistResponseData>;
9
9
  export declare const removeItemFromWishlist: RpcHandler<{
10
10
  itemKey: string;
@@ -1,4 +1,3 @@
1
- import { BAPIError } from "../../errors/index.mjs";
2
1
  import { MIN_WITH_PARAMS_WISHLIST } from "../../constants/index.mjs";
3
2
  function getWithParams(params, context) {
4
3
  return params.with ?? context.withParams?.basket ?? MIN_WITH_PARAMS_WISHLIST;
@@ -25,12 +24,7 @@ export const addItemToWishlist = async function addItemToWishlist2(options, cont
25
24
  } else {
26
25
  const { code, message } = result.wishlist;
27
26
  context.log.error("Adding to wishlist failed", result.wishlist);
28
- throw new BAPIError(
29
- "BAPI ERROR",
30
- code,
31
- message,
32
- "bapiClient.wishlist.addItem"
33
- );
27
+ return new Response(JSON.stringify({ message }), { status: code });
34
28
  }
35
29
  };
36
30
  export const getWishlist = async function getWishlist2(options, context) {
@@ -1,4 +1,4 @@
1
1
  import { RpcContext } from './context';
2
- export type ParamRpcHandler<Params extends Record<string, any>, Response> = (params: Params, context: RpcContext) => Promise<Response> | Response;
3
- export type NoParamRpcHandler<Response> = (context: RpcContext) => Promise<Response> | Response;
2
+ export type ParamRpcHandler<Params extends Record<string, any>, ResponseType> = (params: Params, context: RpcContext) => Promise<ResponseType> | ResponseType;
3
+ export type NoParamRpcHandler<ResponseType> = (context: RpcContext) => Promise<ResponseType> | ResponseType;
4
4
  export type RpcHandler<A, B = void> = B extends void ? NoParamRpcHandler<A> : ParamRpcHandler<A, B>;
@@ -105,6 +105,23 @@ export type NumberOfInstallmentsChosenByTheCustomerForTheOrder = number;
105
105
  export type IfTrueTheCustomerElectedToHaveADelayInPaymentCapture = boolean;
106
106
  export type TimestampOfOrderCreation = string;
107
107
  export type TimestampOfLastOrderUpdate = string;
108
+ export interface ThisFieldHoldsDetailsAboutTheIncludedVATTax {
109
+ amount: TheIncludedVATAmount;
110
+ rate: TheIncludedVATRateInPercentAsIntegerRepresentation;
111
+ }
112
+ /**
113
+ * When an item cannot be shipped within the regular delivery timeframe, and the warehouse is already aware of this, prior to the customer placing the order (ie it is not an unintentionally delayed delivery). This is generally the case when the item is out of stock and: the warehouse is waiting for incoming returns to restock the item, the warehouse has ordered fresh stocks from the supplier/manufacturer and is waiting for these to be shipped to the warehouse.
114
+ */
115
+ export interface DeliveryForecastFromWarehouse {
116
+ deliverable?: {
117
+ key?: string;
118
+ [k: string]: unknown;
119
+ };
120
+ subsequentDelivery?: {
121
+ key?: 'endOfJanuary' | 'endOfFebruary' | 'endOfMarch' | 'endOfApril' | 'endOfMay' | 'endOfJune' | 'endOfJuly' | 'endOfAugust' | 'endOfSeptember' | 'endOfOctober' | 'endOfNovember' | 'endOfDecember' | 'midOfJanuary' | 'midOfFebruary' | 'midOfMarch' | 'midOfApril' | 'midOfMay' | 'midOfJune' | 'midOfJuly' | 'midOfAugust' | 'midOfSeptember' | 'midOfOctober' | 'midOfNovember' | 'midOfDecember' | 'easter' | 'christmas' | 'available' | 'directShipping' | 'outsold';
122
+ [k: string]: unknown;
123
+ };
124
+ }
108
125
  export interface Order {
109
126
  /**
110
127
  * This `id` can be applied as a parameter on the url to retrieve an individual order in the [Fetch Order by ID](#fetch-order-by-id) endpoint.
@@ -535,20 +552,3 @@ export interface Order {
535
552
  createdAt: TimestampOfOrderCreation;
536
553
  updatedAt: TimestampOfLastOrderUpdate;
537
554
  }
538
- export interface ThisFieldHoldsDetailsAboutTheIncludedVATTax {
539
- amount: TheIncludedVATAmount;
540
- rate: TheIncludedVATRateInPercentAsIntegerRepresentation;
541
- }
542
- /**
543
- * When an item cannot be shipped within the regular delivery timeframe, and the warehouse is already aware of this, prior to the customer placing the order (ie it is not an unintentionally delayed delivery). This is generally the case when the item is out of stock and: the warehouse is waiting for incoming returns to restock the item, the warehouse has ordered fresh stocks from the supplier/manufacturer and is waiting for these to be shipped to the warehouse.
544
- */
545
- export interface DeliveryForecastFromWarehouse {
546
- deliverable?: {
547
- key?: string;
548
- [k: string]: unknown;
549
- };
550
- subsequentDelivery?: {
551
- key?: 'endOfJanuary' | 'endOfFebruary' | 'endOfMarch' | 'endOfApril' | 'endOfMay' | 'endOfJune' | 'endOfJuly' | 'endOfAugust' | 'endOfSeptember' | 'endOfOctober' | 'endOfNovember' | 'endOfDecember' | 'midOfJanuary' | 'midOfFebruary' | 'midOfMarch' | 'midOfApril' | 'midOfMay' | 'midOfJune' | 'midOfJuly' | 'midOfAugust' | 'midOfSeptember' | 'midOfOctober' | 'midOfNovember' | 'midOfDecember' | 'easter' | 'christmas' | 'available' | 'directShipping' | 'outsold';
552
- [k: string]: unknown;
553
- };
554
- }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.unwrap = unwrap;
7
+ async function unwrap(response) {
8
+ if (response instanceof Response) {
9
+ console.log("unwrapping for ", response.url);
10
+ return await response.json();
11
+ }
12
+ return response;
13
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Unwrap a possible response into its body
3
+ * @param x
4
+ * @returns
5
+ */
6
+ export declare function unwrap<T>(response: Response | T): Promise<T>;
@@ -0,0 +1,7 @@
1
+ export async function unwrap(response) {
2
+ if (response instanceof Response) {
3
+ console.log("unwrapping for ", response.url);
4
+ return await response.json();
5
+ }
6
+ return response;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-core",
3
- "version": "7.34.1",
3
+ "version": "7.36.0",
4
4
  "description": "Collection of essential utilities to work with the Storefront API",
5
5
  "author": "SCAYLE Commerce Engine",
6
6
  "license": "MIT",
@@ -59,7 +59,7 @@
59
59
  "test:ci": "vitest --run --passWithNoTests --coverage --reporter=default --reporter=junit"
60
60
  },
61
61
  "dependencies": {
62
- "@aboutyou/backbone": "16.0.1",
62
+ "@aboutyou/backbone": "16.0.2",
63
63
  "crypto-js": "4.2.0",
64
64
  "jose": "^4.14.4",
65
65
  "radash": "^11.0.0",
@@ -72,9 +72,9 @@
72
72
  "@scayle/eslint-config-storefront": "3.2.6",
73
73
  "@scayle/prettier-config-storefront": "2.0.2",
74
74
  "@types/crypto-js": "4.2.1",
75
- "@types/node": "20.10.6",
75
+ "@types/node": "20.10.7",
76
76
  "@types/webpack-env": "1.18.4",
77
- "@vitest/coverage-v8": "1.1.1",
77
+ "@vitest/coverage-v8": "1.1.3",
78
78
  "eslint": "8.56.0",
79
79
  "eslint-formatter-gitlab": "5.1.0",
80
80
  "prettier": "3.0.0",
@@ -84,7 +84,7 @@
84
84
  "typescript": "5.3.3",
85
85
  "unbuild": "2.0.0",
86
86
  "unstorage": "1.10.1",
87
- "vitest": "1.1.1"
87
+ "vitest": "1.1.3"
88
88
  },
89
89
  "optionalDependencies": {
90
90
  "redis": "4"