Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify hooks logic #959

Merged
merged 132 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
465bf53
Merge hooks changes from wjh/simplify-hooks
wjhsf Feb 3, 2023
6a03683
lint fixes
wjhsf Feb 3, 2023
e9a3983
Use correct type.
wjhsf Feb 3, 2023
2602899
Remove unnecessary file.
wjhsf Feb 3, 2023
2b7d27f
Add support for updater in cache updates.
wjhsf Feb 6, 2023
90dfab1
Sort imports.
wjhsf Feb 7, 2023
69f2c11
Change `updater` generic from being the same for all to being per fun…
wjhsf Feb 8, 2023
e7bd76d
Clean up cache update matrix.
wjhsf Feb 8, 2023
b0a8715
Rekerjigger cache logic to see what we can do with it.
wjhsf Feb 8, 2023
f12fda1
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 8, 2023
229f650
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 9, 2023
107cd5b
Create options merge util.
wjhsf Feb 9, 2023
ab586ec
Use merged options in query hooks and simplify query keys.
wjhsf Feb 9, 2023
c28d249
Simplify endMatches logic.
wjhsf Feb 9, 2023
623e1de
Add predicate helper to match API config values.
wjhsf Feb 9, 2023
9f550ae
Fix temp test file.
wjhsf Feb 9, 2023
80c0fe8
Use consistent order of generic parameters.
wjhsf Feb 10, 2023
2bd6fc7
Remove pointless line.
wjhsf Feb 10, 2023
6f26e05
Use consistent generic parameter names.
wjhsf Feb 10, 2023
7632df1
Add comments.
wjhsf Feb 10, 2023
8ad426c
More comments.
wjhsf Feb 10, 2023
9e402c2
Remove test directory.
wjhsf Feb 10, 2023
5c5fff0
Generate hooks for all APIs
wjhsf Feb 10, 2023
8b9e7f2
Update Shopper Baskets config from Test directory.
wjhsf Feb 10, 2023
6b30735
Update Shopper Experience query hooks.
wjhsf Feb 10, 2023
b3b36b2
Fix missed merged options type.
wjhsf Feb 13, 2023
71e8831
Add Shopper Login hooks.
wjhsf Feb 13, 2023
0a9ef34
Convert getGiftCertificate from mutation hook to query hook.
wjhsf Feb 13, 2023
d4cdf44
Update Shopper Login hooks.
wjhsf Feb 13, 2023
79930b9
First pass at converting to new cache update matrix.
wjhsf Feb 13, 2023
6a35ad1
Remove canceled Shopper Discovery Search API.
wjhsf Feb 13, 2023
d27786d
Update login helpers.
wjhsf Feb 14, 2023
601b9f3
Fix auth types.
wjhsf Feb 14, 2023
d0e5855
Hopefully avoid caching getGiftCertificate.
wjhsf Feb 14, 2023
7dc671b
Rename shopper login helper to auth helper.
wjhsf Feb 15, 2023
b0f5735
Move auth helper to hooks root.
wjhsf Feb 15, 2023
e6c2ba7
Mark useAuthorizationHeader as internal.
wjhsf Feb 15, 2023
89bd6aa
Rename useAuth to useAuthContext for clarity w/ useAuthHelper.
wjhsf Feb 15, 2023
4cdf3c8
Convert useAuthHelper to default export for consistency.
wjhsf Feb 15, 2023
da93e18
Remove siteId from AuthData, as it is passed via config.
wjhsf Feb 15, 2023
4e727a5
Update comment with generated code.
wjhsf Feb 15, 2023
7e3f613
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 15, 2023
ed97973
Move headers to last parameter because we rarely use it.
wjhsf Feb 15, 2023
dd6adce
Update cache update matrices to new interface.
wjhsf Feb 15, 2023
87b43a9
Refactore test project after api changes.
bendvc Feb 16, 2023
a5f56f7
Clean up cache update logic.
wjhsf Feb 16, 2023
e2377ac
Update names for clarity.
wjhsf Feb 16, 2023
080faf1
Revert test file to version from develop.
wjhsf Feb 16, 2023
973bb6a
Merge remote-tracking branch 'origin/origin/bendvc/hooks-on-develop' …
wjhsf Feb 16, 2023
641138d
Add reminder to revert.
wjhsf Feb 16, 2023
9b6b290
Remove unnecessary default export.
wjhsf Feb 16, 2023
8daf092
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 16, 2023
86fc823
Cache update TODOs should return functions, not throw.
wjhsf Feb 16, 2023
28441ad
Allow user to override authorization header.
wjhsf Feb 16, 2023
f517523
Remove old TODO.
wjhsf Feb 16, 2023
d403b4d
Remove ability to set custom query key.
wjhsf Feb 17, 2023
7a0deab
Replace getQueryKey callback with just declaring query key.
wjhsf Feb 17, 2023
03f455b
Clean up types.
wjhsf Feb 17, 2023
28dcb7b
Rename config.ts to cache.ts
wjhsf Feb 17, 2023
d40554f
Restore type checking test files.
wjhsf Feb 20, 2023
730de3a
Suppress react query error logs during tests.
wjhsf Feb 20, 2023
4a2c86d
Strip unused parameters before generating query key.
wjhsf Feb 20, 2023
3bf4f05
Fix tpe errors.
wjhsf Feb 20, 2023
00ac081
Partially fix type errors.
wjhsf Feb 20, 2023
11fd9eb
Update Shopper Baskets cache logic to use narrower parameters.
wjhsf Feb 20, 2023
382fcb7
Test that all endpoints have hooks.
wjhsf Feb 20, 2023
6bf8272
Create new mutation tests for refactored code.
wjhsf Feb 20, 2023
2dd71ec
Add test to validate all mutations have cache update logic.
wjhsf Feb 20, 2023
17621e4
Alphabetize cache updates.
wjhsf Feb 20, 2023
d49f16a
Simplify mutation tests a bit.
wjhsf Feb 20, 2023
241cdfe
Fix nock adding duplicate request mocks.
wjhsf Feb 21, 2023
859032c
Make failing tests have more helpful failures.
wjhsf Feb 21, 2023
c5ad9c2
Fix tests failing due to missing parameters.
wjhsf Feb 21, 2023
7696a88
Replace old mutation test file with new one.
wjhsf Feb 21, 2023
15e8aea
Remove unused helper type.
wjhsf Feb 21, 2023
98e9fff
Create hook success/error helpers.
wjhsf Feb 21, 2023
6764cb8
Improve parameter matching.
wjhsf Feb 21, 2023
465c748
Add `deleteBasket` tests.
wjhsf Feb 21, 2023
603552d
Add request mock to fix test.
wjhsf Feb 21, 2023
cc0e0c2
Add TODO cache update logic for missing mutations.
wjhsf Feb 21, 2023
acbc12d
Change onSuccess from bound to unbound function.
wjhsf Feb 22, 2023
9efac92
Add test for not implemented mutations.
wjhsf Feb 22, 2023
c39f0a8
Pass not implemented tests.
wjhsf Feb 22, 2023
528d96a
Remove unused import.
wjhsf Feb 22, 2023
1648305
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 22, 2023
1f02ab4
Implement `resetPassword` caching as a no-op.
wjhsf Feb 22, 2023
a5a321e
Add Shopper Baskets query tests.
wjhsf Feb 22, 2023
1db46f0
Add "all endpoints have hooks" tests for all APIs.
wjhsf Feb 22, 2023
874b2ff
Fix failing index tests.
wjhsf Feb 22, 2023
da1c71e
Implement tests for all query hooks.
wjhsf Feb 23, 2023
0ae5349
Remove hooks for `authorizeCustomer` and `getTrustedAgentAuthorizatio…
wjhsf Feb 23, 2023
45b63fd
Update "not implemented" tests to check if cache update logic exists.
wjhsf Feb 23, 2023
48d399d
Extract reused type into type def.
wjhsf Feb 23, 2023
3ce0fa6
Update comment to reflect changed tests.
wjhsf Feb 23, 2023
83c18d0
Remove unnecessary `async`.
wjhsf Feb 23, 2023
32b958a
Implement Shopper Contexts mutation tests.
wjhsf Feb 23, 2023
c2286d9
Rename `makeOptions` to `createOptions`.
wjhsf Feb 23, 2023
271d3a2
Implement Shopper Login mutation tests.
wjhsf Feb 23, 2023
a4ba2e5
Add extra ResponseError assertion.
wjhsf Feb 23, 2023
2972eb2
Update test names.
wjhsf Feb 23, 2023
f78a1c1
Implement Shopper Orders mutation tests.
wjhsf Feb 23, 2023
4a6409d
Convert TODO from throwing to just logging.
wjhsf Feb 23, 2023
4d856af
Fix failing "all endpoints have hooks" tests.
wjhsf Feb 23, 2023
2d66118
Remove unused imports.
wjhsf Feb 23, 2023
8246a6b
Introduce query key helpers.
wjhsf Feb 24, 2023
ca4bc5c
Remove no longer needed query test file.
wjhsf Feb 24, 2023
681085b
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 24, 2023
ea2b699
Update hook usage.
wjhsf Feb 24, 2023
e7073cd
Implement basic Shopper Customers mutation tests.
wjhsf Feb 24, 2023
33d04f0
Export query key types.
wjhsf Feb 24, 2023
448a826
Remove old file.
wjhsf Feb 24, 2023
87933ff
Update cache logic to use query keys instead of predicates.
wjhsf Feb 25, 2023
09d7899
Update parser for proper TypeScript support.
wjhsf Feb 25, 2023
b162e03
Remove unused babel-eslint.
wjhsf Feb 25, 2023
05a0975
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 25, 2023
1ec20ee
Temporarily(?) use internal-lib-build so TypeScript files are properl…
wjhsf Feb 26, 2023
8732c1f
Fix eslint and tsc errors.
wjhsf Feb 26, 2023
f0a119f
Temporarily suppress linter errors.
wjhsf Feb 27, 2023
96347e3
Implement tests for shopper customers mutations that modify a customer.
wjhsf Feb 27, 2023
504773b
Implement full Shopper Customers mutation tests.
wjhsf Feb 28, 2023
cacd83a
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Feb 28, 2023
63f35c8
Rename `StringIndexNever` to `StringIndexToNever`
wjhsf Feb 28, 2023
254b43e
Remove unnecessary invalidation.
wjhsf Feb 28, 2023
081ea67
Update generated comments for hooks.
wjhsf Feb 28, 2023
7d52245
Remove unused variable.
wjhsf Feb 28, 2023
8918178
Remove SLAS `authenticateCustomer` and `getPasswordResetToken` hooks.
wjhsf Mar 1, 2023
bff5174
Remove deprecated Shopper Customers mutations.
wjhsf Mar 1, 2023
a5cc03c
Comment out Shopper Customers endpoints in closed beta.
wjhsf Mar 1, 2023
8a9fdcc
Fix Shopper Customers tests.
wjhsf Mar 1, 2023
4b645c7
Fix Shopper Login tests.
wjhsf Mar 1, 2023
a5b0a40
Update "hook exists" tests to distinguish between "mutation in enum" …
wjhsf Mar 1, 2023
61d8fcb
Merge branch 'develop' into wjh/hooks-on-develop
wjhsf Mar 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 40 additions & 37 deletions packages/commerce-sdk-react/src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Salesforce, Inc.
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
Expand All @@ -12,11 +12,12 @@ import {
ShopperCustomersTypes
} from 'commerce-sdk-isomorphic'
import jwtDecode from 'jwt-decode'
import {ApiClientConfigParams, Argument} from '../hooks/types'
import {ApiClientConfigParams, Prettify, RemoveStringIndex} from '../hooks/types'
import {BaseStorage, LocalStorage, CookieStorage, MemoryStorage, StorageType} from './storage'
import {CustomerType} from '../hooks/useCustomerType'
import {onClient} from '../utils'

type TokenResponse = ShopperLoginTypes.TokenResponse
type Helpers = typeof helpers
interface AuthConfig extends ApiClientConfigParams {
redirectURI: string
Expand All @@ -29,24 +30,25 @@ interface JWTHeaders {
iat: number
}

// this type is slightly different from ShopperLoginTypes.TokenResponse, reasons:
// 1. TokenResponse is too generic (with & {[key:string]: any}), we need a more
// restrictive type to make sure type safe
// 2. The refresh tokens are stored separately for guest and registered user. Instead
// of refresh_token, we have refresh_token_guest and refresh_token_registered
/**
* The extended field is not from api response, we manually store the auth type,
* so we don't need to make another API call when we already have the data.
* Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
* 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
*/
type AuthData = Prettify<
RemoveStringIndex<TokenResponse> & {
customer_type: CustomerType
idp_access_token: string
}
>

/** A shopper could be guest or registered, so we store the refresh tokens individually. */
type AuthDataKeys =
| 'access_token'
| 'customer_id'
| 'enc_user_id'
| 'expires_in'
| 'id_token'
| 'idp_access_token'
| Exclude<keyof AuthData, 'refresh_token'>
| 'refresh_token_guest'
| 'refresh_token_registered'
| 'token_type'
| 'usid'
| 'site_id'
| 'customer_type'

type AuthDataMap = Record<
AuthDataKeys,
{
Expand All @@ -56,16 +58,6 @@ type AuthDataMap = Record<
}
>

/**
* The extended field is not from api response, we manually store the auth type,
* so we don't need to make another API call when we already have the data.
* Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
* 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
*/
type AuthData = ShopperLoginTypes.TokenResponse & {
customer_type: CustomerType
}

/**
* A map of the data that this auth module stores. This maps the name of the property to
* the storage type and the key when stored in that storage. You can also pass in a "callback"
Expand Down Expand Up @@ -118,10 +110,6 @@ const DATA_MAP: AuthDataMap = {
store.delete('cc-nx-g')
}
},
site_id: {
storageType: 'cookie',
key: 'cc-site-id'
},
customer_type: {
storageType: 'local',
key: 'customer_type'
Expand All @@ -140,7 +128,7 @@ class Auth {
private client: ShopperLogin<ApiClientConfigParams>
private shopperCustomersClient: ShopperCustomers<ApiClientConfigParams>
private redirectURI: string
private pendingToken: Promise<ShopperLoginTypes.TokenResponse> | undefined
private pendingToken: Promise<TokenResponse> | undefined
private REFRESH_TOKEN_EXPIRATION_DAYS = 90
private stores: Record<StorageType, BaseStorage>

Expand Down Expand Up @@ -204,9 +192,10 @@ class Auth {
}

private clearStorage() {
Object.keys(DATA_MAP).forEach((keyName) => {
type Key = keyof AuthDataMap
const {key, storageType} = DATA_MAP[keyName as Key]
// Type assertion because Object.keys is silly and limited :(
const keys = Object.keys(DATA_MAP) as AuthDataKeys[]
keys.forEach((keyName) => {
const {key, storageType} = DATA_MAP[keyName]
const store = this.stores[storageType]
store.delete(key)
})
Expand Down Expand Up @@ -244,7 +233,7 @@ class Auth {
* This method stores the TokenResponse object retrived from SLAS, and
* store the data in storage.
*/
private handleTokenResponse(res: ShopperLoginTypes.TokenResponse, isGuest: boolean) {
private handleTokenResponse(res: TokenResponse, isGuest: boolean) {
this.set('access_token', res.access_token)
this.set('customer_id', res.customer_id)
this.set('enc_user_id', res.enc_user_id)
Expand All @@ -268,7 +257,7 @@ class Auth {
*
* @Internal
*/
async queueRequest(fn: () => Promise<ShopperLoginTypes.TokenResponse>, isGuest: boolean) {
async queueRequest(fn: () => Promise<TokenResponse>, isGuest: boolean) {
const queue = this.pendingToken ?? Promise.resolve()
this.pendingToken = queue.then(async () => {
const token = await fn()
Expand Down Expand Up @@ -326,6 +315,20 @@ class Auth {
)
}

/**
* Creates a function that only executes after a session is initialized.
* @param fn Function that needs to wait until the session is initialized.
* @returns Wrapped function
*/
whenReady<Args extends unknown[], Data>(
fn: (...args: Args) => Promise<Data>
): (...args: Args) => Promise<Data> {
return async (...args) => {
await this.ready()
return await fn(...args)
}
}

/**
* A wrapper method for commerce-sdk-isomorphic helper: loginGuestUser.
*
Expand Down
120 changes: 120 additions & 0 deletions packages/commerce-sdk-react/src/hooks/ShopperBaskets/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {ShopperBasketsTypes, ShopperCustomersTypes} from 'commerce-sdk-isomorphic'
import {
ApiClients,
ApiOptions,
CacheUpdate,
CacheUpdateMatrix,
CacheUpdateUpdate,
MergedOptions
} from '../types'
import {and, matchesApiConfig, pathStartsWith} from '../utils'

type Client = ApiClients['shopperBaskets']
type Basket = ShopperBasketsTypes.Basket
type CustomerBasketsResult = ShopperCustomersTypes.BasketsResult
type BasketOptions = MergedOptions<Client, ApiOptions<Basket>>

const updateBasketQuery = (
customerId: string | null,
basketId: string | undefined,
newBasket: Basket
): Pick<CacheUpdate, 'update'> => {
if (!basketId) return {}
const update: Array<CacheUpdateUpdate<Basket> | CacheUpdateUpdate<CustomerBasketsResult>> = [
{
queryKey: ['/baskets', basketId, {basketId}]
}
]
if (customerId) {
const updateCustomerBaskets: CacheUpdateUpdate<CustomerBasketsResult> = {
// Since we use baskets from customer basket query, we need to update it for any basket mutation
queryKey: ['/customers', customerId, '/baskets', {customerId}],
updater: (oldData) => {
// do not update if response basket is not part of existing customer baskets
if (!oldData?.baskets?.some((basket) => basket.basketId === basketId)) {
return undefined
}
const updatedBaskets = oldData.baskets.map((basket) => {
return basket.basketId === basketId ? newBasket : basket
})
return {
...oldData,
// TODO: Remove type assertion when RAML specs match
baskets: updatedBaskets as CustomerBasketsResult['baskets']
}
}
}
update.push(updateCustomerBaskets)
}
// TODO: This type assertion is so that we "forget" what type the updater uses.
// Is there a way to avoid the assertion?
return {update} as CacheUpdate
}

const removeBasketQuery = (
options: BasketOptions,
basketId?: string
): Pick<CacheUpdate, 'remove'> => {
if (!basketId) return {}
return {
remove: [and(matchesApiConfig(options), pathStartsWith(['/baskets', basketId]))]
}
}

const invalidateCustomerBasketsQuery = (
customerId: string | null,
options: BasketOptions
): Pick<CacheUpdate, 'invalidate'> => {
if (!customerId) return {}
return {
invalidate: [
and(matchesApiConfig(options), pathStartsWith(['/customers', customerId, '/baskets']))
]
}
}

const updateBasketFromRequest = (
customerId: string | null,
options: BasketOptions,
response: Basket
): CacheUpdate => ({
...updateBasketQuery(customerId, options.parameters?.basketId, response),
...invalidateCustomerBasketsQuery(customerId, options)
})

const updateBasketFromResponse = (
customerId: string | null,
options: BasketOptions,
response: Basket
): CacheUpdate => ({
...updateBasketQuery(customerId, response.basketId, response),
...invalidateCustomerBasketsQuery(customerId, options)
})

export const cacheUpdateMatrix: CacheUpdateMatrix<Client> = {
addCouponToBasket: updateBasketFromRequest,
addItemToBasket: updateBasketFromRequest,
removeItemFromBasket: updateBasketFromRequest,
addPaymentInstrumentToBasket: updateBasketFromRequest,
createBasket: updateBasketFromResponse, // Response!
deleteBasket: (customerId, options): CacheUpdate => ({
...invalidateCustomerBasketsQuery(customerId, options),
...removeBasketQuery(options)
}),
mergeBasket: updateBasketFromResponse, // Response!
removeCouponFromBasket: updateBasketFromRequest,
removePaymentInstrumentFromBasket: updateBasketFromRequest,
updateBasket: updateBasketFromRequest,
updateBillingAddressForBasket: updateBasketFromRequest,
updateCustomerForBasket: updateBasketFromRequest,
updateItemInBasket: updateBasketFromRequest,
updatePaymentInstrumentInBasket: updateBasketFromRequest,
updateShippingAddressForShipment: updateBasketFromRequest,
updateShippingMethodForShipment: updateBasketFromRequest
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Salesforce, Inc.
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
Expand Down
Loading