Skip to content

Commit 669d1c7

Browse files
committed
Merge branch 'develop' into feature/template-extensibility
* develop: Allow query hook parameters to be `null`. (#1046) Implement `updateCustomerPassword` as no-op. (#1031) Update Retail React App Page Designer integration README (#1041) BUG: Changed type of the phone number field to bring up numberic keyboard on mobile devices - W-9871940 (#1016) Move the MRT reference app to the SDKs, so that we can verify eg. Node support (#966) Update `develop` with `release-v2.7.0` (#1033) Remove unused dependencies. (#1020) Make some style decisions on padding (#1023) Update CHANGELOG.md (#1021) Support product-sets in retail-react-app (#1019) Simplify hooks logic (#959) Fix NPM dependencies (#1012) # Conflicts: # lerna.json # package-lock.json # package.json # packages/commerce-sdk-react/CHANGELOG.md # packages/commerce-sdk-react/package-lock.json # packages/commerce-sdk-react/package.json # packages/internal-lib-build/package-lock.json # packages/internal-lib-build/package.json # packages/pwa-kit-create-app/package-lock.json # packages/pwa-kit-create-app/package.json # packages/pwa-kit-dev/CHANGELOG.md # packages/pwa-kit-dev/package-lock.json # packages/pwa-kit-dev/package.json # packages/pwa-kit-dev/src/configs/webpack/config.js # packages/pwa-kit-dev/src/ssr/server/build-dev-server.js # packages/pwa-kit-react-sdk/CHANGELOG.md # packages/pwa-kit-react-sdk/package-lock.json # packages/pwa-kit-react-sdk/package.json # packages/pwa-kit-runtime/CHANGELOG.md # packages/pwa-kit-runtime/package-lock.json # packages/pwa-kit-runtime/package.json # packages/template-express-minimal/package-lock.json # packages/template-express-minimal/package.json # packages/template-retail-react-app/app/hooks/use-add-to-cart-modal.js # packages/template-retail-react-app/app/partials/product-view/index.jsx # packages/template-retail-react-app/package-lock.json # packages/template-retail-react-app/package.json # packages/template-typescript-minimal/package-lock.json # packages/template-typescript-minimal/package.json # packages/test-commerce-sdk-react/package-lock.json # packages/test-commerce-sdk-react/package.json
2 parents bde07f6 + fc789fe commit 669d1c7

File tree

190 files changed

+11715
-4024
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+11715
-4024
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
uses: "./.github/actions/smoke_tests"
7272

7373
- name: Create MRT credentials file
74-
if: env.IS_NOT_FORK == 'true' && env.IS_LATEST_NPM == 'true' && env.DEVELOP == 'true'
74+
if: env.IS_NOT_FORK == 'true' && env.IS_LATEST_NPM == 'true' && ( env.DEVELOP == 'true' || env.RELEASE == 'true' )
7575
uses: "./.github/actions/create_mrt"
7676
with:
7777
mobify_user: ${{ secrets.MOBIFY_CLIENT_USER }}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
"bump-version": "node ./scripts/bump-version.js",
2525
"local-npm": "node packages/pwa-kit-create-app/scripts/create-mobify-app-dev.js --outputDir local-npm"
2626
}
27-
}
27+
}

packages/commerce-sdk-react/CHANGELOG.md

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
## v2.8.0-dev.0 (Feb 16, 2023)
2-
## v2.8.0-dev.0 (Feb 16, 2023)
3-
## v2.8.0-dev.0 (Feb 15, 2023)
4-
## v2.8.0-dev (Feb 15, 2023)
5-
## v2.8.0-dev (Feb 15, 2023)
6-
## v2.7.0-dev (Jan 25, 2023)
1+
## v2.8.0-dev (Mar 03, 2023)
2+
## v2.7.0 (Mar 03, 2023)
73
- Add Page/Region/Component components for shopper experience/page designer page rendering [#963](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/963)
84
- Namespace `Auth` storage keys with site identifier to allow multi-site support [#911](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/911)
95
- Add Shopper Experience `usePage` and `usePages` hooks[#958](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/958)

packages/commerce-sdk-react/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@
6060
"@types/react-dom": "^17.0.2",
6161
"@types/react-helmet": "^6.1.6",
6262
"cross-env": "^5.2.0",
63-
"internal-lib-build": "^2.7.0-dev",
63+
"internal-lib-build": "^2.8.0-dev",
6464
"jsonwebtoken": "^8.5.1",
6565
"nock": "^13.2.9",
6666
"react": "^17.0.2",
6767
"react-dom": "^17.0.2",
6868
"react-helmet": "^6.1.0",
69+
"semver": "^7.3.8",
70+
"shelljs": "^0.8.5",
6971
"typedoc": "^0.23.5",
7072
"typescript": "^4.7.2",
7173
"watch": "^1.0.2"

packages/commerce-sdk-react/setup-jest.js

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77
import '@testing-library/jest-dom'
8-
import {configure} from '@testing-library/dom'
98
import nock from 'nock'
109

1110
class LocalStorageMock {

packages/commerce-sdk-react/src/auth/index.test.ts

+16-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* SPDX-License-Identifier: BSD-3-Clause
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
7-
import Auth from './'
7+
import Auth, {AuthData} from './'
88
import jwt from 'jsonwebtoken'
99
import {helpers} from 'commerce-sdk-isomorphic'
1010
import * as utils from '../utils'
@@ -39,6 +39,9 @@ jest.mock('../utils', () => ({
3939
onClient: () => true
4040
}))
4141

42+
/** The auth data we store has a slightly different shape than what we use. */
43+
type StoredAuthData = Omit<AuthData, 'refresh_token'> & {refresh_token_guest?: string}
44+
4245
const config = {
4346
clientId: 'clientId',
4447
organizationId: 'organizationId',
@@ -85,7 +88,7 @@ describe('Auth', () => {
8588
test('this.data returns the storage value', () => {
8689
const auth = new Auth(config)
8790

88-
const sample = {
91+
const sample: StoredAuthData = {
8992
refresh_token_guest: 'refresh_token_guest',
9093
access_token: 'access_token',
9194
customer_id: 'customer_id',
@@ -97,7 +100,9 @@ describe('Auth', () => {
97100
usid: 'usid',
98101
customer_type: 'guest'
99102
}
100-
const {refresh_token_guest, ...result} = {...sample, refresh_token: 'refresh_token_guest'}
103+
// Convert stored format to exposed format
104+
const result = {...sample, refresh_token: 'refresh_token_guest'}
105+
delete result.refresh_token_guest
101106

102107
Object.keys(sample).forEach((key) => {
103108
// @ts-expect-error private method
@@ -161,7 +166,7 @@ describe('Auth', () => {
161166
test('ready - re-use valid access token', () => {
162167
const auth = new Auth(config)
163168

164-
const data = {
169+
const data: StoredAuthData = {
165170
refresh_token_guest: 'refresh_token_guest',
166171
access_token: jwt.sign({exp: Math.floor(Date.now() / 1000) + 1000}, 'secret'),
167172
customer_id: 'customer_id',
@@ -173,7 +178,9 @@ describe('Auth', () => {
173178
usid: 'usid',
174179
customer_type: 'guest'
175180
}
176-
const {refresh_token_guest, ...result} = {...data, refresh_token: 'refresh_token_guest'}
181+
// Convert stored format to exposed format
182+
const result = {...data, refresh_token: 'refresh_token_guest'}
183+
delete result.refresh_token_guest
177184

178185
Object.keys(data).forEach((key) => {
179186
// @ts-expect-error private method
@@ -192,7 +199,7 @@ describe('Auth', () => {
192199
test('ready - use refresh token when access token is expired', async () => {
193200
const auth = new Auth(config)
194201

195-
const data = {
202+
const data: StoredAuthData = {
196203
refresh_token_guest: 'refresh_token_guest',
197204
access_token: jwt.sign({exp: Math.floor(Date.now() / 1000) - 1000}, 'secret'),
198205
customer_id: 'customer_id',
@@ -204,7 +211,9 @@ describe('Auth', () => {
204211
usid: 'usid',
205212
customer_type: 'guest'
206213
}
207-
const {refresh_token_guest, ...result} = {...data, refresh_token: 'refresh_token_guest'}
214+
// Convert stored format to exposed format
215+
const result = {...data, refresh_token: 'refresh_token_guest'}
216+
delete result.refresh_token_guest
208217

209218
Object.keys(data).forEach((key) => {
210219
// @ts-expect-error private method

packages/commerce-sdk-react/src/auth/index.ts

+40-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Salesforce, Inc.
2+
* Copyright (c) 2023, Salesforce, Inc.
33
* All rights reserved.
44
* SPDX-License-Identifier: BSD-3-Clause
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
@@ -12,11 +12,12 @@ import {
1212
ShopperCustomersTypes
1313
} from 'commerce-sdk-isomorphic'
1414
import jwtDecode from 'jwt-decode'
15-
import {ApiClientConfigParams, Argument} from '../hooks/types'
15+
import {ApiClientConfigParams, Prettify, RemoveStringIndex} from '../hooks/types'
1616
import {BaseStorage, LocalStorage, CookieStorage, MemoryStorage, StorageType} from './storage'
1717
import {CustomerType} from '../hooks/useCustomerType'
1818
import {onClient} from '../utils'
1919

20+
type TokenResponse = ShopperLoginTypes.TokenResponse
2021
type Helpers = typeof helpers
2122
interface AuthConfig extends ApiClientConfigParams {
2223
redirectURI: string
@@ -30,24 +31,25 @@ interface JWTHeaders {
3031
iat: number
3132
}
3233

33-
// this type is slightly different from ShopperLoginTypes.TokenResponse, reasons:
34-
// 1. TokenResponse is too generic (with & {[key:string]: any}), we need a more
35-
// restrictive type to make sure type safe
36-
// 2. The refresh tokens are stored separately for guest and registered user. Instead
37-
// of refresh_token, we have refresh_token_guest and refresh_token_registered
34+
/**
35+
* The extended field is not from api response, we manually store the auth type,
36+
* so we don't need to make another API call when we already have the data.
37+
* Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
38+
* and it's not easy to grab this info in user land, so we add it into the Auth object, and expose it via a hook
39+
*/
40+
export type AuthData = Prettify<
41+
RemoveStringIndex<TokenResponse> & {
42+
customer_type: CustomerType
43+
idp_access_token: string
44+
}
45+
>
46+
47+
/** A shopper could be guest or registered, so we store the refresh tokens individually. */
3848
type AuthDataKeys =
39-
| 'access_token'
40-
| 'customer_id'
41-
| 'enc_user_id'
42-
| 'expires_in'
43-
| 'id_token'
44-
| 'idp_access_token'
49+
| Exclude<keyof AuthData, 'refresh_token'>
4550
| 'refresh_token_guest'
4651
| 'refresh_token_registered'
47-
| 'token_type'
48-
| 'usid'
49-
| 'site_id'
50-
| 'customer_type'
52+
5153
type AuthDataMap = Record<
5254
AuthDataKeys,
5355
{
@@ -57,16 +59,6 @@ type AuthDataMap = Record<
5759
}
5860
>
5961

60-
/**
61-
* The extended field is not from api response, we manually store the auth type,
62-
* so we don't need to make another API call when we already have the data.
63-
* Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
64-
* and it's not easy to grab this info in user land, so we add it into the Auth object, and expose it via a hook
65-
*/
66-
type AuthData = ShopperLoginTypes.TokenResponse & {
67-
customer_type: CustomerType
68-
}
69-
7062
/**
7163
* A map of the data that this auth module stores. This maps the name of the property to
7264
* the storage type and the key when stored in that storage. You can also pass in a "callback"
@@ -119,10 +111,6 @@ const DATA_MAP: AuthDataMap = {
119111
store.delete('cc-nx-g')
120112
}
121113
},
122-
site_id: {
123-
storageType: 'cookie',
124-
key: 'cc-site-id'
125-
},
126114
customer_type: {
127115
storageType: 'local',
128116
key: 'customer_type'
@@ -141,7 +129,7 @@ class Auth {
141129
private client: ShopperLogin<ApiClientConfigParams>
142130
private shopperCustomersClient: ShopperCustomers<ApiClientConfigParams>
143131
private redirectURI: string
144-
private pendingToken: Promise<ShopperLoginTypes.TokenResponse> | undefined
132+
private pendingToken: Promise<TokenResponse> | undefined
145133
private REFRESH_TOKEN_EXPIRATION_DAYS = 90
146134
private stores: Record<StorageType, BaseStorage>
147135
private fetchedToken: string
@@ -208,9 +196,10 @@ class Auth {
208196
}
209197

210198
private clearStorage() {
211-
Object.keys(DATA_MAP).forEach((keyName) => {
212-
type Key = keyof AuthDataMap
213-
const {key, storageType} = DATA_MAP[keyName as Key]
199+
// Type assertion because Object.keys is silly and limited :(
200+
const keys = Object.keys(DATA_MAP) as AuthDataKeys[]
201+
keys.forEach((keyName) => {
202+
const {key, storageType} = DATA_MAP[keyName]
214203
const store = this.stores[storageType]
215204
store.delete(key)
216205
})
@@ -248,7 +237,7 @@ class Auth {
248237
* This method stores the TokenResponse object retrived from SLAS, and
249238
* store the data in storage.
250239
*/
251-
private handleTokenResponse(res: ShopperLoginTypes.TokenResponse, isGuest: boolean) {
240+
private handleTokenResponse(res: TokenResponse, isGuest: boolean) {
252241
this.set('access_token', res.access_token)
253242
this.set('customer_id', res.customer_id)
254243
this.set('enc_user_id', res.enc_user_id)
@@ -272,7 +261,7 @@ class Auth {
272261
*
273262
* @Internal
274263
*/
275-
async queueRequest(fn: () => Promise<ShopperLoginTypes.TokenResponse>, isGuest: boolean) {
264+
async queueRequest(fn: () => Promise<TokenResponse>, isGuest: boolean) {
276265
const queue = this.pendingToken ?? Promise.resolve()
277266
this.pendingToken = queue.then(async () => {
278267
const token = await fn()
@@ -331,6 +320,20 @@ class Auth {
331320
)
332321
}
333322

323+
/**
324+
* Creates a function that only executes after a session is initialized.
325+
* @param fn Function that needs to wait until the session is initialized.
326+
* @returns Wrapped function
327+
*/
328+
whenReady<Args extends unknown[], Data>(
329+
fn: (...args: Args) => Promise<Data>
330+
): (...args: Args) => Promise<Data> {
331+
return async (...args) => {
332+
await this.ready()
333+
return await fn(...args)
334+
}
335+
}
336+
334337
/**
335338
* A wrapper method for commerce-sdk-isomorphic helper: loginGuestUser.
336339
*

0 commit comments

Comments
 (0)