@akinon/pz-masterpass-rest 1.126.5 → 1.126.6
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/package.json
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
CardModel
|
|
25
25
|
} from '../types/account.types';
|
|
26
26
|
import { useMasterpassToken } from './useMasterpassToken';
|
|
27
|
+
import { decodeMasterpassToken } from '../utils/wait-for-utils-ready';
|
|
27
28
|
|
|
28
29
|
export const useMasterpassAccount = () => {
|
|
29
30
|
const dispatch = useDispatch();
|
|
@@ -132,7 +133,10 @@ export const useMasterpassAccount = () => {
|
|
|
132
133
|
}
|
|
133
134
|
const result = await refetch(options);
|
|
134
135
|
if (result?.data?.token) {
|
|
135
|
-
const decodedToken =
|
|
136
|
+
const decodedToken = decodeMasterpassToken(result.data.token);
|
|
137
|
+
if (!decodedToken) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
136
140
|
return {
|
|
137
141
|
tokenData: decodedToken,
|
|
138
142
|
token: result.data.token,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from '../redux/reducer';
|
|
26
26
|
import { useMasterpassToken } from './useMasterpassToken';
|
|
27
27
|
import { PaymentService } from '../services/payment';
|
|
28
|
+
import { decodeMasterpassToken } from '../utils/wait-for-utils-ready';
|
|
28
29
|
import {
|
|
29
30
|
createPaymentRequest,
|
|
30
31
|
createDirectPaymentRequest,
|
|
@@ -93,7 +94,10 @@ export const useMasterpassPayment = (
|
|
|
93
94
|
const refreshTokenForPayment = useCallback(async () => {
|
|
94
95
|
const result = await refetchToken({ skipReset: true });
|
|
95
96
|
if (result?.data?.token) {
|
|
96
|
-
const decodedToken =
|
|
97
|
+
const decodedToken = decodeMasterpassToken(result.data.token);
|
|
98
|
+
if (!decodedToken) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
97
101
|
return {
|
|
98
102
|
tokenData: decodedToken,
|
|
99
103
|
token: result.data.token,
|
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
updatePaymentState
|
|
15
15
|
} from '../redux/reducer';
|
|
16
16
|
import { isTokenExpired } from '../utils/payment-utils';
|
|
17
|
+
import {
|
|
18
|
+
waitForUtilsReady,
|
|
19
|
+
decodeMasterpassToken
|
|
20
|
+
} from '../utils/wait-for-utils-ready';
|
|
17
21
|
|
|
18
22
|
interface UseMasterpassTokenProps {
|
|
19
23
|
useThreeD: boolean;
|
|
@@ -65,12 +69,37 @@ export const useMasterpassToken = ({
|
|
|
65
69
|
return;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
if (data?.token && data.token !== reduxToken) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
if (!(data?.token && data.token !== reduxToken)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const token = data.token;
|
|
77
|
+
const extras = data.extras;
|
|
78
|
+
let cancelled = false;
|
|
79
|
+
|
|
80
|
+
// The token request can resolve before the Masterpass SDK script has
|
|
81
|
+
// loaded (common on slow/3G networks). Wait for `window.Utils.decodeJwt`
|
|
82
|
+
// to exist before decoding, otherwise the checkout crashes with
|
|
83
|
+
// `Cannot read properties of undefined (reading 'decodeJwt')`.
|
|
84
|
+
//
|
|
85
|
+
// Redux writes are deferred until after the wait resolves: dispatching
|
|
86
|
+
// `setMasterpassRestToken` synchronously would change the `reduxToken`
|
|
87
|
+
// dependency, re-run this effect and cancel the in-flight decode.
|
|
88
|
+
(async () => {
|
|
89
|
+
const ready = await waitForUtilsReady();
|
|
90
|
+
if (cancelled) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
dispatch(setMasterpassRestToken(token));
|
|
95
|
+
dispatch(setMasterpassTerminalGroupId(extras.terminal_group_id));
|
|
96
|
+
dispatch(setMasterpassBankIca(extras.bank_ica));
|
|
97
|
+
|
|
98
|
+
const decodedToken = ready ? decodeMasterpassToken(token) : undefined;
|
|
99
|
+
if (!decodedToken) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
72
102
|
|
|
73
|
-
const decodedToken = window.Utils.decodeJwt(data.token);
|
|
74
103
|
dispatch(setMasterpassRestTokenData(decodedToken));
|
|
75
104
|
|
|
76
105
|
if (decodedToken?.AuthenticationMethod?.toLowerCase() === 'none') {
|
|
@@ -78,7 +107,11 @@ export const useMasterpassToken = ({
|
|
|
78
107
|
}
|
|
79
108
|
|
|
80
109
|
stableOnTokenReady(decodedToken);
|
|
81
|
-
}
|
|
110
|
+
})();
|
|
111
|
+
|
|
112
|
+
return () => {
|
|
113
|
+
cancelled = true;
|
|
114
|
+
};
|
|
82
115
|
}, [data?.token, reduxToken, dispatch, stableOnTokenReady]);
|
|
83
116
|
|
|
84
117
|
const refetchToken = useCallback(
|
|
@@ -94,15 +127,19 @@ export const useMasterpassToken = ({
|
|
|
94
127
|
);
|
|
95
128
|
dispatch(setMasterpassBankIca(result.data.extras.bank_ica));
|
|
96
129
|
|
|
97
|
-
|
|
98
|
-
|
|
130
|
+
await waitForUtilsReady();
|
|
131
|
+
const decodedToken = decodeMasterpassToken(result.data.token);
|
|
99
132
|
|
|
100
|
-
if (decodedToken
|
|
101
|
-
dispatch(
|
|
102
|
-
|
|
133
|
+
if (decodedToken) {
|
|
134
|
+
dispatch(setMasterpassRestTokenData(decodedToken));
|
|
135
|
+
|
|
136
|
+
if (decodedToken?.AuthenticationMethod?.toLowerCase() === 'none') {
|
|
137
|
+
dispatch(updatePaymentState({ useThreeD: false }));
|
|
138
|
+
}
|
|
103
139
|
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
if (options?.three_d !== false && !options?.skipReset) {
|
|
141
|
+
stableOnTokenReady(decodedToken);
|
|
142
|
+
}
|
|
106
143
|
}
|
|
107
144
|
}
|
|
108
145
|
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from './utils/reward-utils';
|
|
|
19
19
|
export * from './utils/card-utils';
|
|
20
20
|
export * from './utils/validation-schemas';
|
|
21
21
|
export * from './utils/masterpass-sdk';
|
|
22
|
+
export * from './utils/wait-for-utils-ready';
|
|
22
23
|
export type { MasterpassEnvironment } from './utils/constants';
|
|
23
24
|
|
|
24
25
|
export * from './types/payment.types';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
2
|
+
const POLL_INTERVAL_MS = 100;
|
|
3
|
+
|
|
4
|
+
interface MasterpassUtils {
|
|
5
|
+
decodeJwt: (token: string) => any;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// `window.Utils` is attached by the Masterpass REST SDK and is undefined until
|
|
10
|
+
// that script finishes loading, so it is resolved through this guarded getter
|
|
11
|
+
// rather than accessed directly.
|
|
12
|
+
const getMasterpassUtils = (): MasterpassUtils | undefined =>
|
|
13
|
+
(window as unknown as { Utils?: MasterpassUtils }).Utils;
|
|
14
|
+
|
|
15
|
+
// The Masterpass REST SDK (`/masterpass-javascript-sdk-web.min.js`) attaches
|
|
16
|
+
// both `window.Masterpass` and `window.Utils` when it finishes loading. That
|
|
17
|
+
// script is loaded asynchronously (see `useMasterpassScript`), so on slow
|
|
18
|
+
// networks the `/orders/masterpass-token` response can arrive before the SDK
|
|
19
|
+
// is ready. Calling `window.Utils.decodeJwt(...)` at that point crashes the
|
|
20
|
+
// checkout with `TypeError: Cannot read properties of undefined (reading
|
|
21
|
+
// 'decodeJwt')` (ZERO-4362 — same class of bug already fixed in the non-rest
|
|
22
|
+
// `@akinon/pz-masterpass` package).
|
|
23
|
+
//
|
|
24
|
+
// This helper polls until the SDK has exposed `window.Utils.decodeJwt`, so
|
|
25
|
+
// callers can await readiness before decoding instead of crashing.
|
|
26
|
+
export const waitForUtilsReady = (
|
|
27
|
+
timeoutMs: number = DEFAULT_TIMEOUT_MS
|
|
28
|
+
): Promise<boolean> =>
|
|
29
|
+
new Promise((resolve) => {
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
|
|
32
|
+
const check = () => {
|
|
33
|
+
if (typeof getMasterpassUtils()?.decodeJwt === 'function') {
|
|
34
|
+
resolve(true);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (Date.now() - start >= timeoutMs) {
|
|
39
|
+
resolve(false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setTimeout(check, POLL_INTERVAL_MS);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
check();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Guarded `decodeJwt` wrapper. Returns `undefined` (instead of throwing) when
|
|
50
|
+
// the SDK is not yet available, so every callsite degrades gracefully.
|
|
51
|
+
export const decodeMasterpassToken = <T = any>(
|
|
52
|
+
token: string
|
|
53
|
+
): T | undefined => {
|
|
54
|
+
const utils = getMasterpassUtils();
|
|
55
|
+
|
|
56
|
+
if (typeof utils?.decodeJwt !== 'function') {
|
|
57
|
+
console.error(
|
|
58
|
+
'[pz-masterpass-rest] window.Utils.decodeJwt is not available'
|
|
59
|
+
);
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return utils.decodeJwt(token);
|
|
64
|
+
};
|