@fat-zebra/sdk 2.0.8-beta.3 → 2.1.0-beta.3
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 +43 -4
- package/README.md +2 -1
- package/dist/react/logging.d.ts +2 -4
- package/dist/react/logging.js +1 -16
- package/dist/react/useFatZebra.js +1 -13
- package/dist/react/useMessage.d.ts +1 -3
- package/dist/react/useMessage.js +16 -60
- package/dist/three_d_secure/index.d.ts +4 -1
- package/dist/three_d_secure/index.js +11 -5
- package/dist/version.js +2 -1
- package/package.json +1 -1
- package/README.dev.md +0 -157
package/CHANGELOG.md
CHANGED
|
@@ -5,103 +5,142 @@ All notable changes to the Fat Zebra JS SDK will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.0] - 2026-06-02
|
|
9
|
+
|
|
10
|
+
> **Upgrade recommended.** This release fixes a critical issue where the React SDK could silently fall back to the legacy 3DS API, which is being decommissioned. Merchants should upgrade to avoid potential production failures.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Removed feature flag to conditionally enable the new ThreeDSecure flow. The ThreeDSecure flow is now always used for authenticating 3DS transactions.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fixed the ThreeDSecure flow failing silently when `accessToken` is supplied via config rather than stored in `localStorage`
|
|
19
|
+
- Fixed an issue where 3DS processing could silently fall back to the legacy 3DS API, which would cause failures once the legacy API is decommissioned
|
|
20
|
+
|
|
8
21
|
## [2.0.6] - 2026-05-27
|
|
9
22
|
|
|
10
23
|
### Added
|
|
24
|
+
|
|
11
25
|
- Improved reliability of the ThreeDSecure flow to prevent duplicate processing when a payment is retried or initiated more than once
|
|
12
26
|
|
|
13
27
|
### Changed
|
|
28
|
+
|
|
14
29
|
- React SDK ThreeDSecure flow brought to parity with the core SDK
|
|
15
30
|
|
|
16
31
|
## [2.0.5] - 2026-05-21
|
|
17
32
|
|
|
18
33
|
### Fixed
|
|
34
|
+
|
|
19
35
|
- Fixed an issue where the device profiling step in the ThreeDSecure flow could trigger card enrollment multiple times if the device profile event fired more than once
|
|
20
36
|
|
|
21
37
|
## [2.0.4] - 2026-05-20
|
|
22
38
|
|
|
23
39
|
### Fixed
|
|
40
|
+
|
|
24
41
|
- Fixed an issue where triggering the ThreeDSecure flow multiple times (e.g. in a single-page application) could register duplicate event listeners, leading to multiple enrollment attempts
|
|
25
42
|
|
|
26
43
|
## [2.0.3] - 2026-05-19
|
|
27
44
|
|
|
28
45
|
### Fixed
|
|
46
|
+
|
|
29
47
|
- Fixed an issue in SPA environments where the Cardinal SCA `payments.validated` handler could accumulate across payment flows, causing stale callbacks to fire on subsequent transactions
|
|
30
48
|
|
|
31
49
|
## [2.0.2] - 2026-05-14
|
|
32
50
|
|
|
33
51
|
### Changed
|
|
52
|
+
|
|
34
53
|
- Default ThreeDSecure challenge window size changed from full-page to 500×600px
|
|
35
54
|
|
|
36
55
|
### Fixed
|
|
56
|
+
|
|
37
57
|
- ThreeDSecure challenge window iframe errors are now correctly reported rather than silently ignored
|
|
38
58
|
|
|
39
59
|
## [2.0.1] - 2026-05-11
|
|
40
60
|
|
|
41
61
|
### Fixed
|
|
62
|
+
|
|
42
63
|
- Resolved an issue causing delayed rendering of the payment form in `renderPaymentsPage`
|
|
43
64
|
- Payment source is now correctly included in SDK tokenisation request events
|
|
44
65
|
|
|
45
66
|
### Security
|
|
67
|
+
|
|
46
68
|
- Bumped axios from 1.13.5 to 1.16.0 to address known vulnerabilities
|
|
47
69
|
|
|
48
70
|
## [2.0.0] - 2026-04-02
|
|
49
71
|
|
|
50
72
|
### Changed
|
|
73
|
+
|
|
51
74
|
- **Upgraded 3DS2 authentication flow** — replaced the previous CyberSource Cardinal/Songbird library with a new SDK-native implementation backed directly by Fat Zebra's infrastructure. The new flow supports a configurable challenge window (250×400, 390×400, 500×600, 600×400, or full-page) and handles device fingerprinting internally. No changes are required to existing integrations; the correct flow is selected automatically.
|
|
52
75
|
|
|
53
76
|
### Security
|
|
77
|
+
|
|
54
78
|
- Bumped handlebars from 4.7.8 to 4.7.9 to address known vulnerabilities
|
|
55
79
|
- Bumped axios to 1.15.0
|
|
56
80
|
|
|
57
81
|
## [1.5.14] - 2026-03-10
|
|
58
82
|
|
|
59
83
|
### Security
|
|
84
|
+
|
|
60
85
|
- Addressed known vulnerabilities in transitive dependencies (axios, minimatch, glob)
|
|
61
86
|
|
|
62
87
|
## [1.5.12] - 2025-10-14
|
|
88
|
+
|
|
63
89
|
## Updated
|
|
90
|
+
|
|
64
91
|
- Bump to react-dom and react 19 from react 18
|
|
65
|
-
- Bump husky from 8.0.3 to 9.1.7
|
|
92
|
+
- Bump husky from 8.0.3 to 9.1.7
|
|
66
93
|
- Bump jest-environment-jsdom from 29.6.1 to 30.2.0
|
|
67
|
-
- Bump nock from 12.0.3 to 13.5.6
|
|
94
|
+
- Bump nock from 12.0.3 to 13.5.6
|
|
68
95
|
- Bump brace-expansion from 1.1.11 to 1.1.12
|
|
69
96
|
- Bump @testing-library/user-event from 14.5.2 to 14.6.1
|
|
70
97
|
|
|
71
98
|
## Improved
|
|
99
|
+
|
|
72
100
|
- Replace webpack with esbuild
|
|
73
101
|
|
|
74
102
|
## [1.5.11] - 2025-09-25
|
|
103
|
+
|
|
75
104
|
## Updated
|
|
105
|
+
|
|
76
106
|
- Bump ts-loader from 9.4.4 to 9.5.4
|
|
107
|
+
|
|
77
108
|
## Improved
|
|
109
|
+
|
|
78
110
|
- added method decorator logging
|
|
79
111
|
|
|
80
112
|
## [1.5.10] - 2025-08-11
|
|
113
|
+
|
|
81
114
|
## Updated
|
|
115
|
+
|
|
82
116
|
- bumped jsdom from ^16.2.1 to jsdom 26.1.0
|
|
83
117
|
- bumped axios from ^1.6.4 to 1.11.0
|
|
84
118
|
|
|
85
119
|
## [1.5.9] - 2025-07-09
|
|
120
|
+
|
|
86
121
|
## Changed
|
|
122
|
+
|
|
87
123
|
- VerifyExistingCard component will now always perform 3DS action. Previously, the VerifyExistingCard would only check if the card had been previously tokenized, unless sca_enabled: true was passed as an option. This update will run SCA regardless.
|
|
88
124
|
|
|
89
125
|
## [1.5.8] – 2025-05-27
|
|
126
|
+
|
|
90
127
|
### Changed
|
|
128
|
+
|
|
91
129
|
- removed yarn.lock in favour of package-lock.json
|
|
92
130
|
|
|
93
131
|
## [1.5.7] – 2025-03-31
|
|
94
132
|
|
|
95
133
|
### Changed
|
|
134
|
+
|
|
96
135
|
Support for 3-D Secure 2.x PARes Status: CHALLENGED
|
|
97
136
|
|
|
98
137
|
- Introduced a new PARes.CHALLENGED enumeration value to represent a "challenge" status in 3-D Secure (3DS) 2.x authentication flows. This is a required change from Cybersouce
|
|
99
138
|
as it will now explicitly handle challenged events. For more information: https://developer.cybersource.com/library/documentation/dev_guides/Payer_Authentication_SCMP_API/html/Topics/Response_FieldsTable23Response_Fields_Field_NameDescriptionReturned_ByData_Type_Lengthauthorizatio-6wc.htm
|
|
100
139
|
|
|
101
|
-
|
|
102
140
|
### Fixed
|
|
103
|
-
- Pass through economic commerce indicator: https://developer.cybersource.com/docs/cybs/en-us/payments/developer/vital/sa/payments/payments-processing-pa-process-intro/payments-processing-pa-eci.html
|
|
104
141
|
|
|
142
|
+
- Pass through economic commerce indicator: https://developer.cybersource.com/docs/cybs/en-us/payments/developer/vital/sa/payments/payments-processing-pa-process-intro/payments-processing-pa-eci.html
|
|
105
143
|
|
|
106
144
|
### Security
|
|
145
|
+
|
|
107
146
|
- Patched routine package updates
|
package/README.md
CHANGED
package/dist/react/logging.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Environment } from "../shared/env";
|
|
2
|
-
import type { TokenizeCardResponse
|
|
2
|
+
import type { TokenizeCardResponse } from "../shared/types";
|
|
3
3
|
type UseFatZebraLogMeta = {
|
|
4
4
|
environment: Environment;
|
|
5
5
|
reference: string;
|
|
@@ -8,6 +8,4 @@ type UseFatZebraLogMeta = {
|
|
|
8
8
|
};
|
|
9
9
|
declare const logUseFatZebra: (args_0: UseFatZebraLogMeta) => UseFatZebraLogMeta;
|
|
10
10
|
declare const logReportTokenizeCardResponse: (args_0: TokenizeCardResponse) => void;
|
|
11
|
-
|
|
12
|
-
declare const logReportRequestThreedsEnabledTimeout: (paymentIntent?: PaymentIntent) => void;
|
|
13
|
-
export { logUseFatZebra, logReportTokenizeCardResponse, logReportThreeDSecureFetched, logReportRequestThreedsEnabledTimeout, };
|
|
11
|
+
export { logUseFatZebra, logReportTokenizeCardResponse, };
|
package/dist/react/logging.js
CHANGED
|
@@ -18,19 +18,4 @@ const logReportTokenizeCardResponse = instrumentFunction("reportTokenizeCardResp
|
|
|
18
18
|
mapArgs: ([data]) => ({ token: data.token, bin: data.bin }),
|
|
19
19
|
className: "useMessage",
|
|
20
20
|
});
|
|
21
|
-
|
|
22
|
-
console.log("three_d_secure fetched", data);
|
|
23
|
-
}, {
|
|
24
|
-
mapArgs: ([data, paymentIntent]) => ({
|
|
25
|
-
data,
|
|
26
|
-
payment_intent: paymentIntent,
|
|
27
|
-
}),
|
|
28
|
-
className: "useMessage",
|
|
29
|
-
});
|
|
30
|
-
const logReportRequestThreedsEnabledTimeout = instrumentFunction("reportRequestThreedsEnabledTimeout", () => {
|
|
31
|
-
console.log("3DS enabled check timed out");
|
|
32
|
-
}, {
|
|
33
|
-
mapArgs: ([paymentIntent]) => ({ payment_intent: paymentIntent }),
|
|
34
|
-
className: "useMessage",
|
|
35
|
-
});
|
|
36
|
-
export { logUseFatZebra, logReportTokenizeCardResponse, logReportThreeDSecureFetched, logReportRequestThreedsEnabledTimeout, };
|
|
21
|
+
export { logUseFatZebra, logReportTokenizeCardResponse, };
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { useEffect
|
|
2
|
-
import * as FatZebra from "../shared/types";
|
|
1
|
+
import { useEffect } from "react";
|
|
3
2
|
import { generatePaymentURL } from "./paymentUrl";
|
|
4
|
-
import Sca from "../sca";
|
|
5
|
-
import GatewayClient from "../shared/api-gateway-client";
|
|
6
3
|
import { generateVerifyURL } from "./verifyUrl";
|
|
7
4
|
import useMessage from "./useMessage";
|
|
8
5
|
import { configureLogger } from "../logging/instrument";
|
|
@@ -10,19 +7,10 @@ import env from "../shared/env";
|
|
|
10
7
|
import { logUseFatZebra } from "./logging";
|
|
11
8
|
const useFatZebra = ({ config, handlers, cardToken }) => {
|
|
12
9
|
const { options, accessToken, paymentIntent, username } = config;
|
|
13
|
-
const sca = useMemo(() => {
|
|
14
|
-
const gatewayClient = new GatewayClient({ accessToken, username, environment: config.environment });
|
|
15
|
-
const successCallback = handlers[FatZebra.PublicEvent.SCA_SUCCESS];
|
|
16
|
-
const failureCallback = handlers[FatZebra.PublicEvent.SCA_ERROR];
|
|
17
|
-
const scaObj = new Sca({ gatewayClient, successCallback, failureCallback, environment: config.environment });
|
|
18
|
-
scaObj.loadScript();
|
|
19
|
-
return scaObj;
|
|
20
|
-
}, [config, username]);
|
|
21
10
|
useMessage({
|
|
22
11
|
paymentIntent,
|
|
23
12
|
options,
|
|
24
13
|
handlers,
|
|
25
|
-
sca,
|
|
26
14
|
config
|
|
27
15
|
});
|
|
28
16
|
useEffect(() => {
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as FatZebra from "../shared/types";
|
|
2
|
-
import Sca from "../sca";
|
|
3
2
|
type UseMessageProps = {
|
|
4
3
|
paymentIntent: FatZebra.PaymentIntent;
|
|
5
4
|
handlers: FatZebra.Handlers;
|
|
6
5
|
options?: FatZebra.OptionalUrlValues;
|
|
7
|
-
sca?: InstanceType<typeof Sca>;
|
|
8
6
|
config?: FatZebra.PaymentConfig;
|
|
9
7
|
};
|
|
10
|
-
declare const useMessage: ({ paymentIntent, options, handlers,
|
|
8
|
+
declare const useMessage: ({ paymentIntent, options, handlers, config }: UseMessageProps) => void;
|
|
11
9
|
export default useMessage;
|
package/dist/react/useMessage.js
CHANGED
|
@@ -15,13 +15,10 @@ import env, { Environment } from "../shared/env";
|
|
|
15
15
|
import { PostMessageClient } from "../shared/post-message-client";
|
|
16
16
|
import { BridgeEvent } from "../shared/types";
|
|
17
17
|
import { setFlowId } from '../logging/logger-context';
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
21
|
-
const isThreeDSecureEnabled = useRef(false);
|
|
18
|
+
import { logReportTokenizeCardResponse } from './logging';
|
|
19
|
+
const useMessage = ({ paymentIntent, options, handlers, config }) => {
|
|
22
20
|
const threeDSecureRef = useRef(null);
|
|
23
21
|
const headlessRef = useRef(null);
|
|
24
|
-
const initAuthClientRef = useRef(null);
|
|
25
22
|
const listenersClientRef = useRef(null);
|
|
26
23
|
// defaults to a resolved promise so handleTokenizeCardResponse doesn't hang if initAuth never runs (no config)
|
|
27
24
|
const authReadyRef = useRef(Promise.resolve());
|
|
@@ -56,7 +53,7 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
56
53
|
});
|
|
57
54
|
if (options && options.sca_enabled) {
|
|
58
55
|
yield authReadyRef.current;
|
|
59
|
-
if (threeDSecureRef.current
|
|
56
|
+
if (threeDSecureRef.current) {
|
|
60
57
|
const iframe = document.querySelector('[name="renderIframe"]');
|
|
61
58
|
const flowId = crypto.randomUUID();
|
|
62
59
|
setFlowId(flowId);
|
|
@@ -70,9 +67,6 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
70
67
|
flowId
|
|
71
68
|
});
|
|
72
69
|
}
|
|
73
|
-
else if (sca) {
|
|
74
|
-
yield sca.run({ paymentIntent, bin: data.bin, cardToken: data.token });
|
|
75
|
-
}
|
|
76
70
|
}
|
|
77
71
|
});
|
|
78
72
|
const messageHandler = (event) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -107,58 +101,21 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
107
101
|
const { el, isExisting } = bridge.load2(env[config.environment].bridgeUrl);
|
|
108
102
|
headlessRef.current = el;
|
|
109
103
|
const initAuth = () => {
|
|
110
|
-
const
|
|
104
|
+
const threeDS = new ThreeDSecure({
|
|
105
|
+
successCallback,
|
|
106
|
+
failureCallback,
|
|
107
|
+
bridge: el,
|
|
108
|
+
environment: config.environment,
|
|
109
|
+
accessToken: config.accessToken,
|
|
110
|
+
});
|
|
111
|
+
threeDSecureRef.current = threeDS;
|
|
112
|
+
const listenersClient = new PostMessageClient({
|
|
111
113
|
channel: 'sca',
|
|
112
114
|
target: el,
|
|
113
115
|
environment: config.environment,
|
|
114
116
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let resolveAuthReady;
|
|
118
|
-
authReadyRef.current = new Promise((resolve) => { resolveAuthReady = resolve; });
|
|
119
|
-
postMessageClient.setEventListeners({
|
|
120
|
-
[BridgeEvent.THREE_D_SECURE_ENABLED]: (data) => {
|
|
121
|
-
const enabled = typeof data === 'boolean' ? data : false;
|
|
122
|
-
if (!resolved) {
|
|
123
|
-
logReportThreeDSecureFetched(enabled, paymentIntent);
|
|
124
|
-
resolved = true;
|
|
125
|
-
isThreeDSecureEnabled.current = enabled;
|
|
126
|
-
resolveAuthReady();
|
|
127
|
-
if (enabled) {
|
|
128
|
-
const threeDS = new ThreeDSecure({
|
|
129
|
-
successCallback,
|
|
130
|
-
failureCallback,
|
|
131
|
-
bridge: el,
|
|
132
|
-
environment: config.environment,
|
|
133
|
-
});
|
|
134
|
-
threeDSecureRef.current = threeDS;
|
|
135
|
-
const listenersClient = new PostMessageClient({
|
|
136
|
-
channel: 'sca',
|
|
137
|
-
target: el,
|
|
138
|
-
environment: config.environment,
|
|
139
|
-
});
|
|
140
|
-
listenersClient.setEventListeners(threeDS.messageHandlers());
|
|
141
|
-
listenersClientRef.current = listenersClient;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
}, { once: true });
|
|
146
|
-
const message = {
|
|
147
|
-
channel: 'sca',
|
|
148
|
-
subject: 'fzi.is-enabled-three-d-secure-req',
|
|
149
|
-
data: {
|
|
150
|
-
merchant: config.username,
|
|
151
|
-
access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
postMessageClient.send(message);
|
|
155
|
-
window.setTimeout(() => {
|
|
156
|
-
if (!resolved) {
|
|
157
|
-
logReportRequestThreedsEnabledTimeout(paymentIntent);
|
|
158
|
-
resolved = true;
|
|
159
|
-
resolveAuthReady();
|
|
160
|
-
}
|
|
161
|
-
}, 500);
|
|
117
|
+
listenersClient.setEventListeners(threeDS.messageHandlers());
|
|
118
|
+
listenersClientRef.current = listenersClient;
|
|
162
119
|
};
|
|
163
120
|
if (isExisting) {
|
|
164
121
|
initAuth();
|
|
@@ -179,10 +136,9 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
179
136
|
};
|
|
180
137
|
}
|
|
181
138
|
return () => {
|
|
182
|
-
var _a
|
|
139
|
+
var _a;
|
|
183
140
|
el.removeEventListener('load', initAuth);
|
|
184
|
-
(_a =
|
|
185
|
-
(_b = listenersClientRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListeners();
|
|
141
|
+
(_a = listenersClientRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListeners();
|
|
186
142
|
};
|
|
187
143
|
}, []);
|
|
188
144
|
useEffect(() => {
|
|
@@ -8,6 +8,7 @@ interface ThreeDSecureConfig {
|
|
|
8
8
|
environment?: Environment;
|
|
9
9
|
bridge: HTMLIFrameElement;
|
|
10
10
|
iframe?: HTMLIFrameElement;
|
|
11
|
+
accessToken?: string;
|
|
11
12
|
}
|
|
12
13
|
interface ThreeDSecureRunProps {
|
|
13
14
|
paymentIntent: PaymentIntent;
|
|
@@ -35,7 +36,9 @@ declare class ThreeDSecure {
|
|
|
35
36
|
private iframe?;
|
|
36
37
|
private deviceProfileReadyHandler;
|
|
37
38
|
private flowId;
|
|
38
|
-
|
|
39
|
+
private accessToken;
|
|
40
|
+
constructor({ successCallback, failureCallback, environment, bridge, accessToken }: ThreeDSecureConfig);
|
|
41
|
+
private getAccessToken;
|
|
39
42
|
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe, flowId }: ThreeDSecureRunProps): void;
|
|
40
43
|
setupResponse(data: DeviceDataCollectionMessage): void;
|
|
41
44
|
messageHandlers(): {
|
|
@@ -19,15 +19,21 @@ import { ChallengeWindowSize } from "../sca/types";
|
|
|
19
19
|
import * as util from "../shared/util";
|
|
20
20
|
import { setFlowId } from "../logging/logger-context";
|
|
21
21
|
class ThreeDSecure {
|
|
22
|
-
constructor({ successCallback, failureCallback, environment, bridge }) {
|
|
22
|
+
constructor({ successCallback, failureCallback, environment, bridge, accessToken }) {
|
|
23
23
|
this.tokenizeOnly = false;
|
|
24
24
|
this.deviceProfileReadyHandler = null;
|
|
25
|
+
this.accessToken = null;
|
|
25
26
|
this.headlessBridge = bridge;
|
|
26
27
|
this.environment = environment;
|
|
27
28
|
this.successCallback = successCallback;
|
|
28
29
|
this.failureCallback = failureCallback;
|
|
30
|
+
this.accessToken = accessToken !== null && accessToken !== void 0 ? accessToken : null;
|
|
29
31
|
DeviceDataCollection.listenDataCollectionResponse(environment);
|
|
30
32
|
}
|
|
33
|
+
getAccessToken() {
|
|
34
|
+
var _a;
|
|
35
|
+
return (_a = this.accessToken) !== null && _a !== void 0 ? _a : window.localStorage.getItem(LocalStorageAccessTokenKey);
|
|
36
|
+
}
|
|
31
37
|
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe, flowId }) {
|
|
32
38
|
console.log('Running 3DS (ThreeDSecure)');
|
|
33
39
|
this.flowId = flowId;
|
|
@@ -102,7 +108,7 @@ class ThreeDSecure {
|
|
|
102
108
|
subject: BridgeEvent.SETUP_THREE_D_SECURE_REQUEST,
|
|
103
109
|
data: {
|
|
104
110
|
flow_id: this.flowId,
|
|
105
|
-
access_token:
|
|
111
|
+
access_token: this.getAccessToken(),
|
|
106
112
|
reference: this.paymentIntent.payment.reference,
|
|
107
113
|
amount: this.paymentIntent.payment.amount,
|
|
108
114
|
currency: this.paymentIntent.payment.currency,
|
|
@@ -116,7 +122,7 @@ class ThreeDSecure {
|
|
|
116
122
|
const message = {
|
|
117
123
|
channel: 'sca',
|
|
118
124
|
subject: BridgeEvent.ENROL_THREE_D_SECURE_REQUEST,
|
|
119
|
-
data: Object.assign(Object.assign(Object.assign({ flow_id: this.flowId, access_token:
|
|
125
|
+
data: Object.assign(Object.assign(Object.assign({ flow_id: this.flowId, access_token: this.getAccessToken(), merchant_username: merchantUsername, card_token: cardToken }, paymentIntent.payment), { verification: paymentIntent.verification, reference_id: cybersourceReferenceId, return_url: `${env[this.environment].returnCybersourceUrl}?flow_id=${this.flowId}`, acs_window_size: (_a = this.challengeWindowSize) !== null && _a !== void 0 ? _a : ChallengeWindowSize.SIZE_500X600, device_channel: "BROWSER" }), snakeCaseKeys(DeviceDataCollection.collectDeviceData()))
|
|
120
126
|
};
|
|
121
127
|
this.headlessBridge.contentWindow.postMessage(message, '*');
|
|
122
128
|
}
|
|
@@ -151,7 +157,7 @@ class ThreeDSecure {
|
|
|
151
157
|
const message = {
|
|
152
158
|
channel: 'sca',
|
|
153
159
|
subject: BridgeEvent.VALIDATE_THREE_D_SECURE_REQUEST,
|
|
154
|
-
data: Object.assign(Object.assign({ flow_id: this.flowId, access_token:
|
|
160
|
+
data: Object.assign(Object.assign({ flow_id: this.flowId, access_token: this.getAccessToken(), merchant_username: this.merchantUsername, card_token: data.cardToken }, this.paymentIntent.payment), { authentication_transaction_id: data.transactionId })
|
|
155
161
|
};
|
|
156
162
|
this.headlessBridge.contentWindow.postMessage(message, '*');
|
|
157
163
|
}
|
|
@@ -179,7 +185,7 @@ class ThreeDSecure {
|
|
|
179
185
|
channel: 'sca',
|
|
180
186
|
subject: BridgeEvent.CREATE_PAYMENT_REQUEST,
|
|
181
187
|
data: {
|
|
182
|
-
access_token:
|
|
188
|
+
access_token: this.getAccessToken(),
|
|
183
189
|
amount: this.paymentIntent.payment.amount,
|
|
184
190
|
card_token: this.cardToken,
|
|
185
191
|
currency: this.paymentIntent.payment.currency,
|
package/dist/version.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
/*! fatzebra-sdk-commit: 5bc4f3388b7a97acd62478a9bfdfa340a80c3847 */
|
|
1
2
|
export const version = '1.5.9';
|
|
2
3
|
// Placeholder replaced at build time by .github/scripts/stamp-version.js with the
|
|
3
4
|
// deployed commit hash (`git rev-parse HEAD`). Stays as the placeholder for builds
|
|
4
5
|
// that don't run the stamp step (e.g. local/package builds).
|
|
5
|
-
export const commitHash = '
|
|
6
|
+
export const commitHash = '5bc4f3388b7a97acd62478a9bfdfa340a80c3847';
|
package/package.json
CHANGED
package/README.dev.md
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# FatZebra-JS
|
|
2
|
-
|
|
3
|
-
**fatzebra.js** (a.k.a JS SDK)is an agent through which various FZ payment functionalies are made available to merchants.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## Architecture Overview
|
|
7
|
-
|
|
8
|
-

|
|
9
|
-
|
|
10
|
-
### API Gateway
|
|
11
|
-
|
|
12
|
-
JS SDk communicates to various FZ backend services from merchant websites's frontend. A valid `access token` needs to be provided to the SDK during initialisation. This grants temporary access to selected services such as Gateway and PayNow. See Obtain Access Token for details
|
|
13
|
-
|
|
14
|
-
The only FZ backend system that the SDK directly interacts with is the API Gateway (AWS API Gateway). Other backend services are hidden behind the API Gateway.
|
|
15
|
-
|
|
16
|
-
### Cross-Frame Communications
|
|
17
|
-
|
|
18
|
-
One of the functionalities provided by the SDK is to load the Hosted Payments Page (HPP) into merchant webpage so that customers can enter their credit card details and make a purchase subsequently. Upon calling the `renderPaymentsPage()` method, the SDK does the following things in order
|
|
19
|
-
|
|
20
|
-
* Create an `<iframe>` DOM element and attach it to the `<div>` specified by the merchant.
|
|
21
|
-
* Load the HPP into `<iframe>`
|
|
22
|
-
* Upon HPP is successfully loaded, the SDK registers a number of event listeners to listen to events coming from the child frame (HPP).
|
|
23
|
-
* Using the combination of the event listeners above as well as the SDK's event registration method `.on()`, events from the child frame can be bubbled up to the merchant page context.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## Development Environment Setup
|
|
27
|
-
|
|
28
|
-
### NPM install
|
|
29
|
-
Install dependencies
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
$ npm install
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Start PayNow
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
$ bundle exec rails -p 3000
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Go to .env.local, ensure PAYNOW_BASE_URL and PAYNOW_BRIDGE_URL have the desired hostname and port number.
|
|
42
|
-
|
|
43
|
-
Upon receiving a request from the SDK, PayNow first extracts the access token from the request header, decodes it, andloads the merchant using the username extracted from the token. Please also ensure that a corresponding merchant record is available in FatZebra Core DB. It must have the same merchant username as the one used for generating the access token previously.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
### Start API Gateway
|
|
47
|
-
**Skip this section if the SDK workflow you are dealing does not involve multiple FZ backend services.**
|
|
48
|
-
|
|
49
|
-
> coming soon...
|
|
50
|
-
|
|
51
|
-
## ApplePay
|
|
52
|
-
### Ngrok tunnelling
|
|
53
|
-
|
|
54
|
-
The setup above would not give us access to Apple Pay's functionalities just yet as they are only available to merchants who have gone through Apple Pay onboarding process, e.g. registering merchant website. FZ has already registered https://fzapplepay.ngrok.io with Apple and this should be used for development.
|
|
55
|
-
|
|
56
|
-
Tunnel PayNow via https://fz-applepay-child.ngrok.io
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
$ ngrok http 4000 -subdomain=fz-applepay-child
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Tunnel Merchant JS via https://fzapplepay.ngrok.io
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
ngrok http -subdomain fzapplepay -host-header="localhost:8080" 8080
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
_Remember to specify host header, otherwise webpack-dev-server will complain._
|
|
69
|
-
|
|
70
|
-
### Visit tunnelled link
|
|
71
|
-
|
|
72
|
-
Visit https://fzapplepay.ngrok.io in Safari. That's all!
|
|
73
|
-
|
|
74
|
-
Webpack-dev-server supports hot reloading, meaning that code changes are reflected on the web page without restarting the server.
|
|
75
|
-
|
|
76
|
-
## Build Javascript
|
|
77
|
-
|
|
78
|
-
There are two npm build scripts in `package.json` for building javascript files.
|
|
79
|
-
|
|
80
|
-
| Command | Output | Description |
|
|
81
|
-
|---------|--------|-------------|
|
|
82
|
-
| npm run build:local | dist/local/fatzebra.js | Used for local dev only. Not saved in S3. |
|
|
83
|
-
| npm run build:staging | dist/staging/fatzebra.js | Used for E2E testing on staging. Saved in S3. Bundle is NOT minified nor uglified. |
|
|
84
|
-
| npm run build:sandbox | dist/sandbox/fatzebra.js | Saved in S3. Bundle is minified and uglified. |
|
|
85
|
-
| npm run build:production | dist/production/fatzebra.js | Saved in S3. Bundle is minified and uglified. |
|
|
86
|
-
|
|
87
|
-
## Deployment Pipeline
|
|
88
|
-
|
|
89
|
-
The JS SDK gets built and delpoyed via github actions https://github.com/fatzebra/fatzebra-js/actions. The pipeline is defined in `.github/workflows/ci.yml`
|
|
90
|
-
|
|
91
|
-
The deployed SDKs are available from the following URLs.
|
|
92
|
-
|
|
93
|
-
* Test: https://cdn.pmnts-staging.io/sdk/v1/fatzebra.js
|
|
94
|
-
* Sandbox: https://cdn.pmnts-sandbox.io/sdk/v1/fatzebra.js
|
|
95
|
-
* Production: https://cdn.pmnts.io/sdk/v1/fatzebra.js
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
## Release Management
|
|
99
|
-
|
|
100
|
-
### NPM
|
|
101
|
-
|
|
102
|
-
Releases are based on tags. There are two types of releases:
|
|
103
|
-
- Production
|
|
104
|
-
- Beta
|
|
105
|
-
|
|
106
|
-
To perform a production release:
|
|
107
|
-
|
|
108
|
-
```shell
|
|
109
|
-
git tag -a v1.5.10 -m "Production Release: 1.5.10"
|
|
110
|
-
git push origin v1.5.10
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
**NOTE:** Production releases will only work when on the `main` branch
|
|
114
|
-
|
|
115
|
-
To perform a beta release
|
|
116
|
-
|
|
117
|
-
```shell
|
|
118
|
-
git tag -a v1.5.10-beta.0 -m "Beta: 1.5.10-beta.0"
|
|
119
|
-
git push origin v1.5.10-beta.0
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### CDN
|
|
123
|
-
|
|
124
|
-
## Staging
|
|
125
|
-
|
|
126
|
-
Staging is released automatically for each branch (on push)
|
|
127
|
-
|
|
128
|
-
## Sandbox
|
|
129
|
-
|
|
130
|
-
Sandbox deployment will trigger when pushing through a tag with beta in it on the `main` branch.
|
|
131
|
-
|
|
132
|
-
Running this on main will trigger sandbox deployment (as well as npm beta release):
|
|
133
|
-
|
|
134
|
-
```shell
|
|
135
|
-
git tag -a v1.5.10-beta.0 -m "Beta: 1.5.10-beta.0"
|
|
136
|
-
git push origin v1.5.10-beta.0
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Additionally, the pipeline will trigger a cypress integration spec on sandbox which will run here: https://github.com/fatzebra/gazelle/actions
|
|
140
|
-
Ensure this pipeline is green before deploying to production and then post a link of the outcome
|
|
141
|
-
|
|
142
|
-
## Production
|
|
143
|
-
|
|
144
|
-
Production deployment will _ONLY_ trigger on the main branch and when pushing through a tag WITHOUT beta in it.
|
|
145
|
-
|
|
146
|
-
Running this on main will trigger production deployment:
|
|
147
|
-
|
|
148
|
-
```shell
|
|
149
|
-
git tag -a v1.5.10 -m "Beta: 1.5.10"
|
|
150
|
-
git push origin v1.5.10
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Rollback management
|
|
154
|
-
|
|
155
|
-
The pipeline will upload a version to override the existing deployment, but also a version of the build to a folder in s3.
|
|
156
|
-
|
|
157
|
-
|