@fat-zebra/sdk 2.0.1-beta.2 → 2.0.1-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/dist/hpp/hpp.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import Sca from '../sca';
2
2
  import { ChallengeWindowSize } from '../sca/types';
3
3
  import { Customer, PaymentIntent } from '../shared/types';
4
+ import ThreeDSecure from "../three_d_secure";
4
5
  declare const HPP_DEFAULT_OPTIONS: {
5
6
  [key: string]: boolean | string;
6
7
  };
@@ -11,6 +12,8 @@ interface HppModuleConfig {
11
12
  customer: Customer;
12
13
  username: string;
13
14
  sca: Sca;
15
+ threeDSecure: ThreeDSecure;
16
+ isThreeDSecureEnabled: () => boolean;
14
17
  test?: boolean;
15
18
  }
16
19
  interface HppLoadParams {
@@ -42,7 +45,7 @@ declare class Hpp {
42
45
  private customer;
43
46
  private username;
44
47
  private sca;
45
- private ThreeDSecure;
48
+ private threeDSecure;
46
49
  private cardToken;
47
50
  private postMessageClient;
48
51
  private test;
@@ -50,9 +53,11 @@ declare class Hpp {
50
53
  private headlessLoaded;
51
54
  private headlessPreviouslyLoaded;
52
55
  private iframeLoaded;
53
- private threeDSecureEnabled;
56
+ private isThreeDSecureEnabled;
54
57
  private challengeWindowSize;
55
58
  private scaHandler;
59
+ private crossFrameListenersBound;
60
+ private publicEventListenersBound;
56
61
  constructor(config: HppModuleConfig);
57
62
  setListenersAndEmitReady(): void;
58
63
  load(config: HppLoadParams): void;
@@ -62,6 +67,7 @@ declare class Hpp {
62
67
  }): string;
63
68
  setCrossFramesEventListeners(): void;
64
69
  setPublicEventListeners(): void;
70
+ destroy(): void;
65
71
  createPurchase(extra?: {
66
72
  [key: string]: boolean | string;
67
73
  }): void;
package/dist/hpp/hpp.js CHANGED
@@ -12,7 +12,6 @@ import { BridgeEvent, PublicEvent, } from '../shared/types';
12
12
  import * as util from '../shared/util';
13
13
  import { setTransactionReference } from "../logging/logger-context";
14
14
  import { logMethod } from "../logging/logMethod";
15
- import ThreeDSecure from "../three_d_secure";
16
15
  import env from "../shared/env";
17
16
  import { configureLogger } from "../logging/instrument";
18
17
  const HPP_DEFAULT_OPTIONS = {
@@ -22,7 +21,6 @@ const HPP_DEFAULT_OPTIONS = {
22
21
  };
23
22
  class Hpp {
24
23
  constructor(config) {
25
- this.threeDSecureEnabled = false;
26
24
  this.paymentIntent = config.paymentIntent;
27
25
  this.customer = config.customer;
28
26
  this.username = config.username;
@@ -32,53 +30,50 @@ class Hpp {
32
30
  this.headlessLoaded = false;
33
31
  this.headlessPreviouslyLoaded = false;
34
32
  this.iframeLoaded = false;
35
- this.postMessageClient = new PostMessageClient({
36
- channel: 'sca',
37
- target: this.iframe
38
- });
33
+ this.threeDSecure = config.threeDSecure;
34
+ this.isThreeDSecureEnabled = config.isThreeDSecureEnabled;
35
+ this.crossFrameListenersBound = false;
36
+ this.publicEventListenersBound = false;
39
37
  configureLogger({
40
38
  baseUrl: env[process.env.API_ENV].payNowUrl
41
39
  });
42
40
  }
43
41
  setListenersAndEmitReady() {
44
- const message = {
45
- channel: 'sca',
46
- subject: BridgeEvent.READY,
47
- data: {}
48
- };
49
- if (this.headlessLoaded && this.iframeLoaded) {
50
- // initial headless load
51
- this.ThreeDSecure = new ThreeDSecure({
52
- bridge: this.headless,
53
- environment: process.env.API_ENV,
54
- iframe: this.iframe
55
- });
42
+ if (!this.crossFrameListenersBound) {
56
43
  this.setCrossFramesEventListeners();
57
- this.setPublicEventListeners();
44
+ this.crossFrameListenersBound = true;
45
+ }
46
+ if (this.headlessLoaded && this.iframeLoaded) {
47
+ if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled()) {
48
+ this.setPublicEventListeners();
49
+ this.publicEventListenersBound = true;
50
+ }
58
51
  emit(PublicEvent.HPP_READY);
59
- this.iframe.contentWindow.postMessage(message, '*');
60
52
  }
61
53
  else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
62
- this.ThreeDSecure = new ThreeDSecure({
63
- bridge: this.headless,
64
- environment: process.env.API_ENV,
65
- iframe: this.iframe
66
- });
67
- this.iframe.contentWindow.postMessage(message, '*');
68
54
  // subsequent iframe loads after headless has been previously loaded
69
55
  // this caters for the SPA scenario
56
+ if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled()) {
57
+ this.setPublicEventListeners();
58
+ this.publicEventListenersBound = true;
59
+ }
70
60
  emit(PublicEvent.HPP_READY);
71
61
  }
72
62
  }
73
63
  load(config) {
74
- this.challengeWindowSize = config.options.challengeWindowSize;
64
+ var _a;
65
+ this.challengeWindowSize = (_a = config.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize;
75
66
  setTransactionReference(config.paymentIntent.payment.reference);
76
- this.hppOptions = config.options;
67
+ this.hppOptions = config.options || {};
77
68
  const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
78
69
  this.headless = el;
79
70
  this.headlessPreviouslyLoaded = isExisting;
80
71
  this.iframe = document.createElement('iframe');
81
72
  document.getElementById(config.containerId).appendChild(this.iframe);
73
+ this.postMessageClient = new PostMessageClient({
74
+ channel: 'sca',
75
+ target: this.iframe
76
+ });
82
77
  this.headless.onload = () => {
83
78
  this.headlessLoaded = true;
84
79
  this.setListenersAndEmitReady();
@@ -87,6 +82,10 @@ class Hpp {
87
82
  this.iframeLoaded = true;
88
83
  this.setListenersAndEmitReady();
89
84
  };
85
+ if (this.headlessPreviouslyLoaded) {
86
+ this.headlessLoaded = true;
87
+ this.setListenersAndEmitReady();
88
+ }
90
89
  const payNowUrl = this.getPayNowUrl(config.options);
91
90
  this.iframe.setAttribute("src", payNowUrl);
92
91
  this.iframe.setAttribute('allow', 'payment');
@@ -146,13 +145,15 @@ class Hpp {
146
145
  if (this.hppOptions.tokenizeOnly)
147
146
  return;
148
147
  if (this.hppOptions.enableSca) {
149
- if (this.threeDSecureEnabled) {
150
- this.ThreeDSecure.run({
148
+ if (this.isThreeDSecureEnabled()) {
149
+ this.threeDSecure.run({
151
150
  paymentIntent: this.paymentIntent,
152
151
  merchantUsername: this.username,
153
152
  cardToken: this.cardToken,
154
153
  test: this.test,
155
- challengeWindowSize: this.challengeWindowSize
154
+ challengeWindowSize: this.challengeWindowSize,
155
+ iframe: this.iframe,
156
+ tokenizeOnly: false
156
157
  });
157
158
  return; // do not continue execution to old 3DS
158
159
  }
@@ -215,16 +216,7 @@ class Hpp {
215
216
  data: data,
216
217
  });
217
218
  };
218
- handlers[BridgeEvent.THREE_D_SECURE_ENABLED] = (data) => {
219
- this.threeDSecureEnabled = typeof data === "boolean" ? data : false;
220
- if (this.threeDSecureEnabled) {
221
- // setPublicEventListeners is set before this feature flag is returned.
222
- // we need to therefore unset the scaHandler (for the old implementation or we will get two purchase requests
223
- off(PublicEvent.SCA_SUCCESS, this.scaHandler);
224
- }
225
- };
226
- const handlersIncludingThreeDSecure = Object.assign(Object.assign({}, handlers), this.ThreeDSecure.messageHandlers());
227
- this.postMessageClient.setEventListeners(handlersIncludingThreeDSecure);
219
+ this.postMessageClient.setEventListeners(handlers);
228
220
  }
229
221
  setPublicEventListeners() {
230
222
  this.scaHandler = (event) => {
@@ -236,6 +228,12 @@ class Hpp {
236
228
  };
237
229
  on(PublicEvent.SCA_SUCCESS, this.scaHandler);
238
230
  }
231
+ destroy() {
232
+ if (this.publicEventListenersBound && this.scaHandler) {
233
+ off(PublicEvent.SCA_SUCCESS, this.scaHandler);
234
+ this.publicEventListenersBound = false;
235
+ }
236
+ }
239
237
  createPurchase(extra = null) {
240
238
  const message = {
241
239
  channel: 'sca',
package/dist/main.d.ts CHANGED
@@ -27,11 +27,17 @@ export default class FatZebra {
27
27
  private sca;
28
28
  private fzConfig;
29
29
  private gatewayClient;
30
+ private headless;
31
+ private threeDSecure;
32
+ private threeDSEnabled;
33
+ private threeDSecureListenersBound;
30
34
  constructor(config: FZConfig);
31
- tokenizeCard(card: Card, headless: HTMLIFrameElement): void;
32
- cardDidTokenize(headless: HTMLIFrameElement, callback: (data: any) => void): void;
35
+ tokenizeCard(card: Card): void;
36
+ cardDidTokenize(callback: (data: any) => void): void;
37
+ private requestThreeDSEnabled;
33
38
  verifyCard(params: VerifyCardParams): Promise<void>;
34
- renderPaymentsPage(params: HppLoadParams): void;
39
+ setThreeDSecureListeners(): void;
40
+ renderPaymentsPage(params: HppLoadParams): Promise<void>;
35
41
  renderApplePayButton(params: ApplePayParams): void;
36
42
  renderClickToPay(params: HppClickToPayParams): void;
37
43
  checkout(): void;
package/dist/main.js CHANGED
@@ -23,12 +23,15 @@ import { toHumanizedErrors, validateClickToPayLoadParams, validateHppLoadParams,
23
23
  import GatewayClient from './shared/api-gateway-client';
24
24
  import { Hpp } from './hpp';
25
25
  import ClickToPay from './click_to_pay';
26
- import { validateApplePayLoadParams } from "./validation/validators/apple-pay-load-params-button-validator";
27
- import { ApplePay } from "./applepay";
28
- import { setLoggerUsername } from "./logging/logger-context";
29
- import { logMethod } from "./logging/logMethod";
26
+ import { validateApplePayLoadParams } from './validation/validators/apple-pay-load-params-button-validator';
27
+ import { ApplePay } from './applepay';
28
+ import { setLoggerUsername } from './logging/logger-context';
29
+ import { logMethod } from './logging/logMethod';
30
+ import ThreeDSecure from './three_d_secure';
30
31
  export default class FatZebra {
31
32
  constructor(config) {
33
+ this.threeDSEnabled = false;
34
+ this.threeDSecureListenersBound = false;
32
35
  setLoggerUsername(config.username);
33
36
  this.fzConfig = config;
34
37
  window.MerchantUsername = config.username;
@@ -40,29 +43,47 @@ export default class FatZebra {
40
43
  gatewayClient: this.gatewayClient,
41
44
  });
42
45
  this.sca.loadScript();
46
+ const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
47
+ this.headless = el;
48
+ this.threeDSecure = new ThreeDSecure({
49
+ bridge: this.headless,
50
+ environment: process.env.API_ENV,
51
+ });
52
+ if (isExisting) {
53
+ this.setThreeDSecureListeners();
54
+ }
55
+ else {
56
+ this.headless.onload = () => {
57
+ this.setThreeDSecureListeners();
58
+ };
59
+ }
60
+ const message = {
61
+ channel: 'sca',
62
+ subject: BridgeEvent.READY,
63
+ data: {},
64
+ };
65
+ window.top.postMessage(message, '*');
43
66
  }
44
- tokenizeCard(card, headless) {
67
+ tokenizeCard(card) {
45
68
  const channel = 'sca';
46
- headless.onload = () => {
47
- const message = {
48
- channel,
49
- subject: BridgeEvent.TOKENIZE_CARD_REQUEST,
50
- data: {
51
- access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
52
- card_holder: card.holder,
53
- card_number: card.number,
54
- card_expiry: `${card.expiryMonth}/${card.expiryYear}`,
55
- cvv: card.cvv,
56
- }
57
- };
58
- headless.contentWindow.postMessage(message, '*');
69
+ const message = {
70
+ channel,
71
+ subject: BridgeEvent.TOKENIZE_CARD_REQUEST,
72
+ data: {
73
+ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
74
+ card_holder: card.holder,
75
+ card_number: card.number,
76
+ card_expiry: `${card.expiryMonth}/${card.expiryYear}`,
77
+ cvv: card.cvv,
78
+ },
59
79
  };
80
+ this.headless.contentWindow.postMessage(message, '*');
60
81
  }
61
- cardDidTokenize(headless, callback) {
82
+ cardDidTokenize(callback) {
62
83
  const channel = 'sca';
63
84
  const postMessageClient = new PostMessageClient({
64
85
  channel,
65
- target: headless
86
+ target: this.headless,
66
87
  });
67
88
  const handlers = {};
68
89
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
@@ -70,85 +91,183 @@ export default class FatZebra {
70
91
  };
71
92
  postMessageClient.setEventListeners(handlers);
72
93
  }
94
+ requestThreeDSEnabled() {
95
+ return new Promise((resolve) => {
96
+ var _a;
97
+ const channel = 'sca';
98
+ const postMessageClient = new PostMessageClient({
99
+ channel,
100
+ target: this.headless,
101
+ });
102
+ let resolved = false;
103
+ postMessageClient.setEventListeners({
104
+ [BridgeEvent.THREE_D_SECURE_ENABLED]: (data) => {
105
+ const enabled = typeof data === 'boolean' ? data : false;
106
+ this.threeDSEnabled = enabled;
107
+ if (!resolved) {
108
+ resolved = true;
109
+ resolve(enabled);
110
+ }
111
+ },
112
+ });
113
+ const message = {
114
+ channel,
115
+ subject: 'fzi.is-enabled-three-d-secure-req',
116
+ data: {
117
+ merchant: this.fzConfig.username,
118
+ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
119
+ },
120
+ };
121
+ (_a = this.headless.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, '*');
122
+ window.setTimeout(() => {
123
+ if (!resolved) {
124
+ resolved = true;
125
+ resolve(false);
126
+ }
127
+ }, 5000);
128
+ });
129
+ }
73
130
  verifyCard(params) {
74
131
  return __awaiter(this, void 0, void 0, function* () {
75
- var _a;
132
+ var _a, _b;
76
133
  const valid = validateVerifyCardParams(params);
77
134
  if (!valid) {
78
135
  emit(PublicEvent.VALIDATION_ERROR, {
79
136
  errors: toHumanizedErrors(validateVerifyCardParams.errors),
80
- data: null
137
+ data: null,
81
138
  });
82
139
  return;
83
140
  }
141
+ const threeDSEnabled = yield this.requestThreeDSEnabled();
84
142
  switch (params.paymentMethod.type) {
85
- case PaymentMethodType.CARD:
86
- const headless = bridge.load(process.env.PAYNOW_BRIDGE_URL);
143
+ case PaymentMethodType.CARD: {
87
144
  const card = params.paymentMethod.data;
88
- this.cardDidTokenize(headless, (data) => __awaiter(this, void 0, void 0, function* () {
89
- var _a;
90
- const bin = card.number.substr(0, 6);
145
+ this.cardDidTokenize((data) => __awaiter(this, void 0, void 0, function* () {
146
+ var _a, _b;
147
+ if (threeDSEnabled) {
148
+ this.threeDSecure.run({
149
+ paymentIntent: params.paymentIntent,
150
+ cardToken: data.token,
151
+ merchantUsername: this.fzConfig.username,
152
+ challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
153
+ test: this.fzConfig.test,
154
+ tokenizeOnly: true,
155
+ });
156
+ }
157
+ else {
158
+ const bin = card.number.substr(0, 6);
159
+ this.sca.run({
160
+ cardToken: data.token,
161
+ customer: params.customer,
162
+ paymentIntent: params.paymentIntent,
163
+ bin,
164
+ challengeWindowSize: (_b = params.options) === null || _b === void 0 ? void 0 : _b.challengeWindowSize,
165
+ });
166
+ }
167
+ }));
168
+ this.tokenizeCard(card);
169
+ break;
170
+ }
171
+ case PaymentMethodType.CARD_ON_FILE: {
172
+ const cardToken = params.paymentMethod.data.token;
173
+ if (threeDSEnabled) {
174
+ this.threeDSecure.run({
175
+ paymentIntent: params.paymentIntent,
176
+ cardToken,
177
+ merchantUsername: this.fzConfig.username,
178
+ challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
179
+ test: this.fzConfig.test,
180
+ tokenizeOnly: true,
181
+ });
182
+ }
183
+ else {
184
+ const bin = (yield this.gatewayClient.getCard({
185
+ card_token: cardToken,
186
+ })).data.bin;
91
187
  this.sca.run({
92
- cardToken: data.token,
188
+ cardToken,
93
189
  customer: params.customer,
94
190
  paymentIntent: params.paymentIntent,
95
191
  bin,
96
- challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
192
+ challengeWindowSize: (_b = params.options) === null || _b === void 0 ? void 0 : _b.challengeWindowSize,
97
193
  });
98
- }));
99
- this.tokenizeCard(card, headless);
100
- break;
101
- case PaymentMethodType.CARD_ON_FILE:
102
- const cardToken = params.paymentMethod.data.token;
103
- const bin = (yield this.gatewayClient.getCard({ card_token: cardToken })).data.bin;
104
- this.sca.run({
105
- cardToken,
106
- customer: params.customer,
107
- paymentIntent: params.paymentIntent,
108
- bin,
109
- challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
110
- });
194
+ }
111
195
  break;
196
+ }
112
197
  }
113
198
  });
114
199
  }
200
+ setThreeDSecureListeners() {
201
+ var _a;
202
+ if (this.threeDSecureListenersBound)
203
+ return;
204
+ this.threeDSecureListenersBound = true;
205
+ const channel = 'sca';
206
+ const postMessageClient = new PostMessageClient({
207
+ channel,
208
+ target: this.headless,
209
+ });
210
+ const handlers = this.threeDSecure.messageHandlers();
211
+ handlers[BridgeEvent.THREE_D_SECURE_ENABLED] = (data) => {
212
+ this.threeDSEnabled = typeof data === 'boolean' ? data : false;
213
+ };
214
+ postMessageClient.setEventListeners(handlers);
215
+ const message = {
216
+ channel,
217
+ subject: 'fzi.is-enabled-three-d-secure-req',
218
+ data: {
219
+ merchant: this.fzConfig.username,
220
+ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
221
+ },
222
+ };
223
+ (_a = this.headless.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, '*');
224
+ }
115
225
  renderPaymentsPage(params) {
116
- const valid = validateHppLoadParams(params);
117
- if (!valid) {
118
- emit(PublicEvent.VALIDATION_ERROR, {
119
- errors: toHumanizedErrors(validateHppLoadParams.errors),
120
- data: null
226
+ return __awaiter(this, void 0, void 0, function* () {
227
+ var _a;
228
+ const valid = validateHppLoadParams(params);
229
+ if (!valid) {
230
+ emit(PublicEvent.VALIDATION_ERROR, {
231
+ errors: toHumanizedErrors(validateHppLoadParams.errors),
232
+ data: null,
233
+ });
234
+ return;
235
+ }
236
+ yield this.requestThreeDSEnabled();
237
+ if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
238
+ window.HPP.destroy();
239
+ }
240
+ window.HPP = new Hpp({
241
+ version: params.version,
242
+ paymentIntent: params.paymentIntent,
243
+ customer: params.customer,
244
+ username: this.fzConfig.username,
245
+ sca: this.sca,
246
+ test: this.fzConfig.test,
247
+ threeDSecure: this.threeDSecure,
248
+ isThreeDSecureEnabled: () => this.threeDSEnabled,
121
249
  });
122
- return;
123
- }
124
- window.HPP = new Hpp({
125
- version: params.version,
126
- paymentIntent: params.paymentIntent,
127
- customer: params.customer,
128
- username: this.fzConfig.username,
129
- sca: this.sca,
130
- test: this.fzConfig.test,
250
+ window.HPP.load(params);
131
251
  });
132
- window.HPP.load(params);
133
252
  }
134
253
  renderApplePayButton(params) {
135
254
  const valid = validateApplePayLoadParams(params);
136
255
  if (!valid) {
137
256
  emit(PublicEvent.VALIDATION_ERROR, {
138
257
  errors: toHumanizedErrors(validateApplePayLoadParams.errors),
139
- data: null
258
+ data: null,
140
259
  });
141
260
  return;
142
261
  }
143
262
  window.ApplePayButton = new ApplePay({
144
263
  environment: params.environment,
145
264
  paymentIntent: params.paymentIntent,
146
- username: this.fzConfig.username
265
+ username: this.fzConfig.username,
147
266
  });
148
267
  window.ApplePayButton.load({
149
268
  containerId: params.containerId,
150
269
  paymentIntent: params.paymentIntent,
151
- options: params.options
270
+ options: params.options,
152
271
  });
153
272
  }
154
273
  renderClickToPay(params) {
@@ -156,7 +275,7 @@ export default class FatZebra {
156
275
  if (!valid) {
157
276
  emit(PublicEvent.VALIDATION_ERROR, {
158
277
  errors: toHumanizedErrors(validateClickToPayLoadParams.errors),
159
- data: null
278
+ data: null,
160
279
  });
161
280
  return;
162
281
  }
@@ -40,11 +40,14 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
40
40
  });
41
41
  }
42
42
  if (options && options.sca_enabled && threeDSecureEnabled) {
43
+ const iframe = document.querySelector('[name="renderIframe"]');
43
44
  threeDSecureRef.current.run({
44
45
  paymentIntent,
45
46
  cardToken: data.token,
46
47
  merchantUsername: config.username,
47
- test: config.environment !== Environment.production
48
+ test: config.environment !== Environment.production,
49
+ tokenizeOnly: config.options.tokenize_only,
50
+ iframe: iframe
48
51
  });
49
52
  return;
50
53
  }
@@ -66,13 +69,11 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
66
69
  const headless = el;
67
70
  let onMessage;
68
71
  headless.onload = () => {
69
- const iframe = document.querySelector('[name="renderIframe"]');
70
72
  const threeDS = new ThreeDSecure({
71
73
  successCallback,
72
74
  failureCallback,
73
75
  bridge: headless,
74
76
  environment: config.environment,
75
- iframe: iframe
76
77
  });
77
78
  threeDSecureRef.current = threeDS;
78
79
  const messages = threeDS.messageHandlers(); // { [subject]: (payload) => void }
@@ -1,7 +1,7 @@
1
- declare const bridgeUrl = "https://paynow.test/sdk/bridge";
1
+ declare const bridgeUrl = "http://localhost:3006/sdk/bridge";
2
2
  declare const apiUrl = "https://api.test/sdk";
3
3
  declare const payNowUrl = "https://paynow.test";
4
4
  declare const songbirdUrl = "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js";
5
5
  declare const cybersourceUrl = "https://centinelapistag.cardinalcommerce.com";
6
- declare const returnCybersourceUrl = "https://paynow.test/return";
6
+ declare const returnCybersourceUrl = "https://48e5-115-130-65-211.ngrok-free.app/return";
7
7
  export { bridgeUrl, apiUrl, payNowUrl, songbirdUrl, cybersourceUrl, returnCybersourceUrl };
@@ -1,7 +1,7 @@
1
- const bridgeUrl = "https://paynow.test/sdk/bridge";
1
+ const bridgeUrl = "http://localhost:3006/sdk/bridge";
2
2
  const apiUrl = "https://api.test/sdk";
3
3
  const payNowUrl = "https://paynow.test";
4
4
  const songbirdUrl = "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js";
5
5
  const cybersourceUrl = "https://centinelapistag.cardinalcommerce.com";
6
- const returnCybersourceUrl = "https://paynow.test/return";
6
+ const returnCybersourceUrl = "https://48e5-115-130-65-211.ngrok-free.app/return";
7
7
  export { bridgeUrl, apiUrl, payNowUrl, songbirdUrl, cybersourceUrl, returnCybersourceUrl };
@@ -20,14 +20,17 @@ declare class ThreeDSecure {
20
20
  private challengeWindowSize;
21
21
  private successCallback;
22
22
  private failureCallback;
23
+ private tokenizeOnly;
23
24
  private iframe?;
24
- constructor({ successCallback, failureCallback, environment, bridge, iframe }: ThreeDSecureConfig);
25
- run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test }: {
25
+ constructor({ successCallback, failureCallback, environment, bridge }: ThreeDSecureConfig);
26
+ run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: {
26
27
  paymentIntent: PaymentIntent;
27
28
  cardToken: string;
28
29
  merchantUsername: string;
29
30
  challengeWindowSize?: ChallengeWindowSize;
30
31
  test: boolean;
32
+ tokenizeOnly?: boolean;
33
+ iframe?: HTMLIFrameElement;
31
34
  }): void;
32
35
  setupResponse(data: DeviceDataCollectionMessage): void;
33
36
  messageHandlers(): {
@@ -41,6 +44,7 @@ declare class ThreeDSecure {
41
44
  private validateAuthentication;
42
45
  private validationAuthenticationResponse;
43
46
  private createPurchase;
47
+ private listenDeviceCollectionReady;
44
48
  private setLoading;
45
49
  }
46
50
  export default ThreeDSecure;
@@ -18,15 +18,18 @@ import { getThreeDSecureValidationResult } from "./utility/getValidationResult";
18
18
  import { ChallengeWindowSize } from "../sca/types";
19
19
  import * as util from "../shared/util";
20
20
  class ThreeDSecure {
21
- constructor({ successCallback, failureCallback, environment, bridge, iframe }) {
21
+ constructor({ successCallback, failureCallback, environment, bridge }) {
22
+ this.tokenizeOnly = false;
22
23
  this.headlessBridge = bridge;
23
24
  this.environment = environment;
24
25
  this.successCallback = successCallback;
25
26
  this.failureCallback = failureCallback;
26
- this.iframe = iframe;
27
27
  DeviceDataCollection.listenDataCollectionResponse(environment);
28
+ this.listenDeviceCollectionReady();
28
29
  }
29
- run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test }) {
30
+ run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }) {
31
+ this.iframe = iframe;
32
+ this.tokenizeOnly = tokenizeOnly;
30
33
  this.setLoading();
31
34
  this.paymentIntent = paymentIntent;
32
35
  this.test = test;
@@ -45,12 +48,6 @@ class ThreeDSecure {
45
48
  handlers[BridgeEvent.SETUP_THREE_D_SECURE_SUCCESS_RESPONSE] = (data) => {
46
49
  this.setupResponse(data);
47
50
  };
48
- on(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, () => this.checkEnrollment({
49
- paymentIntent: this.paymentIntent,
50
- cardToken: this.cardToken,
51
- merchantUsername: this.merchantUsername,
52
- cybersourceReferenceId: this.cybersourceReferenceId,
53
- }));
54
51
  handlers[BridgeEvent.ENROL_THREE_D_SECURE_RESPONSE] = (data) => {
55
52
  this.enrolmentResponse(data);
56
53
  };
@@ -61,7 +58,7 @@ class ThreeDSecure {
61
58
  this.validationAuthenticationResponse(data);
62
59
  };
63
60
  handlers[BridgeEvent.THREE_D_SECURE_FAILURE_RESPONSE] = (data) => {
64
- emit(PublicEvent.SCA_ERROR, { errors: [data.errors], data: data });
61
+ emit(PublicEvent.SCA_ERROR, { errors: [data.errors], data });
65
62
  };
66
63
  return handlers;
67
64
  }
@@ -123,6 +120,8 @@ class ThreeDSecure {
123
120
  }
124
121
  if (scenario.outcome.success) {
125
122
  this.reportSuccess(`FatZebra.3DS: 3DS success - ${scenario.description}.`, threeDSecureData);
123
+ if (this.tokenizeOnly)
124
+ return; // DO NO process purchase if tokenizing only.
126
125
  const extra = util.toObjectWithSnakeCaseKeys(threeDSecureData);
127
126
  this.createPurchase(extra);
128
127
  return;
@@ -149,6 +148,8 @@ class ThreeDSecure {
149
148
  const extra = util.toObjectWithSnakeCaseKeys(threeDSecureData);
150
149
  if (scenario.outcome.success) {
151
150
  this.reportSuccess(`FatZebra.3DS: 3DS success - ${scenario.description}.`, threeDSecureData);
151
+ if (this.tokenizeOnly)
152
+ return; // DO NO process purchase if tokenizing only.
152
153
  this.createPurchase(extra);
153
154
  }
154
155
  else {
@@ -176,6 +177,14 @@ class ThreeDSecure {
176
177
  message.data.extra = Object.assign(Object.assign({}, extra), { sli: toFzSli(extra.eci) });
177
178
  this.headlessBridge.contentWindow.postMessage(message, '*');
178
179
  }
180
+ listenDeviceCollectionReady() {
181
+ on(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, () => this.checkEnrollment({
182
+ paymentIntent: this.paymentIntent,
183
+ cardToken: this.cardToken,
184
+ merchantUsername: this.merchantUsername,
185
+ cybersourceReferenceId: this.cybersourceReferenceId,
186
+ }));
187
+ }
179
188
  setLoading(loading = true) {
180
189
  var _a;
181
190
  if ((_a = this === null || this === void 0 ? void 0 : this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) {
@@ -12,7 +12,6 @@ export default class DeviceDataCollection {
12
12
  private static readonly INPUT_ID;
13
13
  createIframe(): void;
14
14
  static listenDataCollectionResponse(environment: Environment): void;
15
- private static hasEmittedProfileReady;
16
15
  private static handleDataCollectionResponse;
17
16
  private static handleCollectionResponse;
18
17
  static collectDeviceData(): DeviceDataType;
@@ -50,18 +50,14 @@ class DeviceDataCollection {
50
50
  // https://developer.cybersource.com/docs/cybs/en-us/payer-authentication/developer/all/so/payer-auth/pa2-ccdc-ddc-intro.html#reference_qmk_jrl_xpb
51
51
  if (event.origin !== env[environment].cybersourceUrl)
52
52
  return;
53
- if (this.hasEmittedProfileReady)
54
- return;
55
53
  this.handleCollectionResponse(event);
56
54
  }
57
55
  static handleCollectionResponse(event) {
58
56
  const response = JSON.parse(event.data);
59
57
  if (response["MessageType"] == "profile.completed") {
60
- this.hasEmittedProfileReady = true;
61
58
  emit(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, { message: null, data: null });
62
59
  }
63
60
  else if (response["Status"] == false) {
64
- this.hasEmittedProfileReady = true;
65
61
  // Still proceed, even if status is false (as per recommendations from cybersource support team.
66
62
  emit(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, { message: null, data: null });
67
63
  }
@@ -126,7 +122,6 @@ DeviceDataCollection.IFRAME_ID = "cardinal_collection_iframe";
126
122
  DeviceDataCollection.IFRAME_NAME = "collectionIframe";
127
123
  DeviceDataCollection.FORM_ID = "cardinal_collection_form";
128
124
  DeviceDataCollection.INPUT_ID = "cardinal_collection_form_input";
129
- DeviceDataCollection.hasEmittedProfileReady = false;
130
125
  export default DeviceDataCollection;
131
126
  __decorate([
132
127
  logMethod({
@@ -66,11 +66,6 @@ class ThreeDSecureChallengeWindow {
66
66
  });
67
67
  content.appendChild(frameWrap);
68
68
  overlay.appendChild(content);
69
- // Backdrop click to close (optional)
70
- overlay.addEventListener("click", (e) => {
71
- if (e.target === overlay)
72
- ThreeDSecureChallengeWindow.hide();
73
- });
74
69
  document.body.appendChild(overlay);
75
70
  return { overlay, content, frameWrap };
76
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fat-zebra/sdk",
3
- "version": "2.0.1-beta.2",
3
+ "version": "2.0.1-beta.3",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {