@fat-zebra/sdk 2.0.1-beta.9 → 2.0.2-beta.1

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
@@ -13,7 +13,7 @@ interface HppModuleConfig {
13
13
  username: string;
14
14
  sca: Sca;
15
15
  threeDSecure: ThreeDSecure;
16
- requestThreeDSEnabled: () => Promise<boolean>;
16
+ isThreeDSecureEnabled?: boolean;
17
17
  test?: boolean;
18
18
  }
19
19
  interface HppLoadParams {
@@ -54,13 +54,12 @@ declare class Hpp {
54
54
  private headlessPreviouslyLoaded;
55
55
  private iframeLoaded;
56
56
  private isThreeDSecureEnabled;
57
- private requestThreeDSEnabled;
58
57
  private challengeWindowSize;
59
58
  private scaHandler;
60
59
  private crossFrameListenersBound;
61
60
  private publicEventListenersBound;
62
61
  constructor(config: HppModuleConfig);
63
- setListenersAndEmitReady(): Promise<void>;
62
+ setListenersAndEmitReady(): void;
64
63
  load(config: HppLoadParams): void;
65
64
  purchase(): void;
66
65
  getPayNowUrl(options?: {
@@ -72,5 +71,6 @@ declare class Hpp {
72
71
  createPurchase(extra?: {
73
72
  [key: string]: boolean | string;
74
73
  }): void;
74
+ private reportHppStatus;
75
75
  }
76
76
  export { Hpp, type HppLoadParams, HPP_DEFAULT_OPTIONS, };
package/dist/hpp/hpp.js CHANGED
@@ -4,14 +4,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
- step((generator = generator.apply(thisArg, _arguments || [])).next());
14
- });
7
+ var __rest = (this && this.__rest) || function (s, e) {
8
+ var t = {};
9
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
10
+ t[p] = s[p];
11
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
12
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
13
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
14
+ t[p[i]] = s[p[i]];
15
+ }
16
+ return t;
15
17
  };
16
18
  import * as bridge from '../shared/bridge-client';
17
19
  import { LocalStorageAccessTokenKey } from '../shared/constants';
@@ -30,6 +32,7 @@ const HPP_DEFAULT_OPTIONS = {
30
32
  };
31
33
  class Hpp {
32
34
  constructor(config) {
35
+ var _a;
33
36
  this.isThreeDSecureEnabled = false;
34
37
  this.paymentIntent = config.paymentIntent;
35
38
  this.customer = config.customer;
@@ -41,38 +44,35 @@ class Hpp {
41
44
  this.headlessPreviouslyLoaded = false;
42
45
  this.iframeLoaded = false;
43
46
  this.threeDSecure = config.threeDSecure;
44
- this.requestThreeDSEnabled = config.requestThreeDSEnabled;
45
47
  this.crossFrameListenersBound = false;
46
48
  this.publicEventListenersBound = false;
49
+ this.isThreeDSecureEnabled = (_a = config.isThreeDSecureEnabled) !== null && _a !== void 0 ? _a : false;
47
50
  configureLogger({
48
51
  baseUrl: env[process.env.API_ENV].payNowUrl
49
52
  });
50
53
  }
51
54
  setListenersAndEmitReady() {
52
- return __awaiter(this, void 0, void 0, function* () {
53
- if (!this.crossFrameListenersBound) {
54
- this.setCrossFramesEventListeners();
55
- this.crossFrameListenersBound = true;
56
- }
57
- if (this.headlessLoaded && this.iframeLoaded) {
58
- this.isThreeDSecureEnabled = yield this.requestThreeDSEnabled();
59
- if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
60
- this.setPublicEventListeners();
61
- this.publicEventListenersBound = true;
62
- }
63
- emit(PublicEvent.HPP_READY);
55
+ this.reportHppStatus(this);
56
+ if (!this.crossFrameListenersBound) {
57
+ this.setCrossFramesEventListeners();
58
+ this.crossFrameListenersBound = true;
59
+ }
60
+ if (this.headlessLoaded && this.iframeLoaded) {
61
+ if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
62
+ this.setPublicEventListeners();
63
+ this.publicEventListenersBound = true;
64
64
  }
65
- else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
66
- this.isThreeDSecureEnabled = yield this.requestThreeDSEnabled();
67
- // subsequent iframe loads after headless has been previously loaded
68
- // this caters for the SPA scenario
69
- if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
70
- this.setPublicEventListeners();
71
- this.publicEventListenersBound = true;
72
- }
73
- emit(PublicEvent.HPP_READY);
65
+ emit(PublicEvent.HPP_READY);
66
+ }
67
+ else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
68
+ // subsequent iframe loads after headless has been previously loaded
69
+ // this caters for the SPA scenario
70
+ if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
71
+ this.setPublicEventListeners();
72
+ this.publicEventListenersBound = true;
74
73
  }
75
- });
74
+ emit(PublicEvent.HPP_READY);
75
+ }
76
76
  }
77
77
  load(config) {
78
78
  var _a;
@@ -136,9 +136,12 @@ class Hpp {
136
136
  return queryString ? `${base}?${searchParams.toString()}` : `${base}`;
137
137
  }
138
138
  setCrossFramesEventListeners() {
139
+ console.log('setCrossFramesEventListeners');
139
140
  const handlers = {};
140
141
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
141
142
  var _a;
143
+ if (data.source === 'verifyCard')
144
+ return;
142
145
  if (data.errors) {
143
146
  emit(PublicEvent.TOKENIZATION_ERROR, {
144
147
  message: 'Card tokenization failed.',
@@ -172,6 +175,7 @@ class Hpp {
172
175
  return; // do not continue execution to old 3DS
173
176
  }
174
177
  this.sca.run({
178
+ source: 'hpp',
175
179
  cardToken: data.token,
176
180
  customer: this.customer,
177
181
  paymentIntent: this.paymentIntent,
@@ -233,11 +237,14 @@ class Hpp {
233
237
  this.postMessageClient.setEventListeners(handlers);
234
238
  }
235
239
  setPublicEventListeners() {
240
+ console.log('setPublicEventListeners');
236
241
  this.scaHandler = (event) => {
242
+ if (event.detail.data.source === 'verifyCard')
243
+ return;
237
244
  if (this.hppOptions.tokenizeOnly)
238
245
  return;
239
246
  const threedsData = event.detail.data;
240
- const extra = util.toObjectWithSnakeCaseKeys(threedsData);
247
+ const _a = util.toObjectWithSnakeCaseKeys(threedsData), { source } = _a, extra = __rest(_a, ["source"]);
241
248
  this.createPurchase(extra);
242
249
  };
243
250
  on(PublicEvent.SCA_SUCCESS, this.scaHandler);
@@ -247,8 +254,13 @@ class Hpp {
247
254
  off(PublicEvent.SCA_SUCCESS, this.scaHandler);
248
255
  this.publicEventListenersBound = false;
249
256
  }
257
+ if (this.crossFrameListenersBound) {
258
+ this.postMessageClient.removeEventListeners();
259
+ this.crossFrameListenersBound = false;
260
+ }
250
261
  }
251
262
  createPurchase(extra = null) {
263
+ console.log('createPurchase');
252
264
  const message = {
253
265
  channel: 'sca',
254
266
  subject: BridgeEvent.CREATE_PAYMENT_REQUEST,
@@ -268,8 +280,33 @@ class Hpp {
268
280
  }
269
281
  this.headless.contentWindow.postMessage(message, '*');
270
282
  }
283
+ reportHppStatus(hpp) {
284
+ }
271
285
  }
286
+ __decorate([
287
+ logMethod()
288
+ ], Hpp.prototype, "setCrossFramesEventListeners", null);
289
+ __decorate([
290
+ logMethod()
291
+ ], Hpp.prototype, "setPublicEventListeners", null);
272
292
  __decorate([
273
293
  logMethod()
274
294
  ], Hpp.prototype, "createPurchase", null);
295
+ __decorate([
296
+ logMethod({
297
+ mapArgs: (args) => {
298
+ const hpp = args[0];
299
+ return [
300
+ {
301
+ crossFrameListenersBound: hpp.crossFrameListenersBound,
302
+ publicEventListenersBound: hpp.publicEventListenersBound,
303
+ isThreeDSecureEnabled: hpp.isThreeDSecureEnabled,
304
+ headlessLoaded: hpp.headlessLoaded,
305
+ headlessPreviouslyLoaded: hpp.headlessPreviouslyLoaded,
306
+ iframeLoaded: hpp.iframeLoaded,
307
+ },
308
+ ];
309
+ },
310
+ })
311
+ ], Hpp.prototype, "reportHppStatus", null);
275
312
  export { Hpp, HPP_DEFAULT_OPTIONS, };
@@ -2,6 +2,7 @@ export type LogOptions<A extends unknown[]> = {
2
2
  endpoint?: string | ((...args: A) => string);
3
3
  mapArgs?: (args: A) => unknown;
4
4
  enabled?: () => boolean;
5
+ className?: string;
5
6
  };
6
7
  type LoggerConfig = {
7
8
  baseUrl?: string;
@@ -17,7 +17,6 @@ function sendLog(endpoint, payload) {
17
17
  void axios.post(endpoint, payload);
18
18
  }
19
19
  else {
20
- // fallback for non-browser or older environments
21
20
  void axios.post(endpoint, payload);
22
21
  }
23
22
  }
@@ -38,6 +37,7 @@ export function instrumentFunction(methodName, fn, opts = {}) {
38
37
  const payload = {
39
38
  username: getLoggerUsername(),
40
39
  reference: getTransactionReference(),
40
+ className: opts.className,
41
41
  method: methodName,
42
42
  arguments: mapArgs(args),
43
43
  timestamp: new Date().toISOString(),
@@ -31,13 +31,16 @@ import { instrumentFunction } from "./instrument";
31
31
  // Decorator factory
32
32
  export function logMethod(opts = {}) {
33
33
  return function (target, propertyKey, descriptor) {
34
- var _a;
34
+ var _a, _b;
35
35
  const original = descriptor.value;
36
36
  if (typeof original !== "function") {
37
37
  console.error(`@logMethod can only decorate methods (${propertyKey})`);
38
38
  return descriptor;
39
39
  }
40
- descriptor.value = instrumentFunction(propertyKey, original, Object.assign(Object.assign({}, opts), { mapArgs: (_a = opts.mapArgs) !== null && _a !== void 0 ? _a : ((args) => args.map((a) => {
40
+ const className = typeof target === "function"
41
+ ? target.name || "UnknownClass"
42
+ : ((_a = target === null || target === void 0 ? void 0 : target.constructor) === null || _a === void 0 ? void 0 : _a.name) || "UnknownClass";
43
+ descriptor.value = instrumentFunction(propertyKey, original, Object.assign(Object.assign({}, opts), { className, mapArgs: (_b = opts.mapArgs) !== null && _b !== void 0 ? _b : ((args) => args.map((a) => {
41
44
  if (!a || typeof a !== "object")
42
45
  return a;
43
46
  return Object.assign(Object.assign({}, a), { js_sdk: true });
package/dist/main.d.ts CHANGED
@@ -30,18 +30,21 @@ export default class FatZebra {
30
30
  private headless;
31
31
  private threeDSecure;
32
32
  private threeDSecureListenersBound;
33
+ private isThreeDSecureEnabled;
34
+ private bridgeReady;
35
+ private authReady;
33
36
  constructor(config: FZConfig);
37
+ private setAuthImpl;
34
38
  tokenizeCard(card: Card): void;
35
39
  cardDidTokenize(callback: (data: any) => void): void;
36
- private requestThreeDSEnabled;
40
+ private requestThreeDSecureEnabled;
37
41
  verifyCard(params: VerifyCardParams): Promise<void>;
38
- setThreeDSecureListeners(): void;
39
42
  renderPaymentsPage(params: HppLoadParams): void;
40
43
  renderApplePayButton(params: ApplePayParams): void;
41
44
  renderClickToPay(params: HppClickToPayParams): void;
42
- reportThreeDSecureFetchedOnInit(data: any): void;
43
- reportThreeDSecureFetched(data: any, paymentIntent?: PaymentIntent): void;
44
- reportRequestThreedsEnabledTimeout(paymentIntent?: PaymentIntent): void;
45
+ private setThreeDSecureListeners;
46
+ private reportThreeDSecureFetched;
47
+ private reportRequestThreedsEnabledTimeout;
45
48
  checkout(): void;
46
49
  on(event: PublicEvent, callback: (e: any) => void): void;
47
50
  off(event: PublicEvent, callback: (e: any) => void): void;
package/dist/main.js CHANGED
@@ -25,12 +25,15 @@ import { Hpp } from './hpp';
25
25
  import ClickToPay from './click_to_pay';
26
26
  import { validateApplePayLoadParams } from './validation/validators/apple-pay-load-params-button-validator';
27
27
  import { ApplePay } from './applepay';
28
- import { setLoggerUsername } from './logging/logger-context';
28
+ import { setLoggerUsername, setTransactionReference } from './logging/logger-context';
29
29
  import { logMethod } from './logging/logMethod';
30
30
  import ThreeDSecure from './three_d_secure';
31
31
  export default class FatZebra {
32
32
  constructor(config) {
33
+ var _a;
33
34
  this.threeDSecureListenersBound = false;
35
+ this.isThreeDSecureEnabled = false;
36
+ console.log('initialising');
34
37
  setLoggerUsername(config.username);
35
38
  this.fzConfig = config;
36
39
  window.MerchantUsername = config.username;
@@ -38,32 +41,43 @@ export default class FatZebra {
38
41
  username: config.username,
39
42
  environment: process.env.API_ENV,
40
43
  });
41
- this.sca = new Sca({
42
- gatewayClient: this.gatewayClient,
43
- });
44
- this.sca.loadScript();
45
44
  const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
46
45
  this.headless = el;
47
- this.threeDSecure = new ThreeDSecure({
48
- bridge: this.headless,
49
- environment: process.env.API_ENV,
50
- });
51
46
  if (isExisting) {
52
- console.log('headless exists');
53
- this.setThreeDSecureListeners();
47
+ this.bridgeReady = Promise.resolve();
54
48
  }
55
49
  else {
56
- this.headless.addEventListener('load', () => {
57
- console.log('headless loaded');
58
- this.setThreeDSecureListeners();
50
+ this.bridgeReady = new Promise((resolve) => {
51
+ this.headless.addEventListener('load', () => resolve());
59
52
  });
60
53
  }
54
+ this.authReady = this.setAuthImpl();
61
55
  const message = {
62
56
  channel: 'sca',
63
57
  subject: BridgeEvent.READY,
64
58
  data: {},
65
59
  };
66
- window.top.postMessage(message, '*');
60
+ (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage(message, '*');
61
+ }
62
+ setAuthImpl() {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ console.log('setAuthImpl()');
65
+ yield this.bridgeReady;
66
+ this.isThreeDSecureEnabled = yield this.requestThreeDSecureEnabled(500);
67
+ if (this.isThreeDSecureEnabled) {
68
+ this.threeDSecure = new ThreeDSecure({
69
+ bridge: this.headless,
70
+ environment: process.env.API_ENV,
71
+ });
72
+ this.setThreeDSecureListeners();
73
+ }
74
+ else {
75
+ this.sca = new Sca({
76
+ gatewayClient: this.gatewayClient,
77
+ });
78
+ this.sca.loadScript();
79
+ }
80
+ });
67
81
  }
68
82
  tokenizeCard(card) {
69
83
  const channel = 'sca';
@@ -71,6 +85,7 @@ export default class FatZebra {
71
85
  channel,
72
86
  subject: BridgeEvent.TOKENIZE_CARD_REQUEST,
73
87
  data: {
88
+ source: 'verifyCard',
74
89
  access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
75
90
  card_holder: card.holder,
76
91
  card_number: card.number,
@@ -90,51 +105,51 @@ export default class FatZebra {
90
105
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
91
106
  callback(data);
92
107
  };
93
- postMessageClient.setEventListeners(handlers);
108
+ postMessageClient.setEventListeners(handlers, { once: true });
94
109
  }
95
- requestThreeDSEnabled(timeout, paymentIntent) {
96
- console.log('requestThreeDSEnabled');
97
- return new Promise((resolve) => {
98
- const channel = 'sca';
99
- const postMessageClient = new PostMessageClient({
100
- channel,
101
- target: this.headless,
102
- });
103
- let resolved = false;
104
- postMessageClient.setEventListeners({
105
- [BridgeEvent.THREE_D_SECURE_ENABLED]: (data) => {
106
- const enabled = typeof data === 'boolean' ? data : false;
110
+ requestThreeDSecureEnabled(timeout, paymentIntent) {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ console.log('requestThreeDSEnabled');
113
+ return new Promise((resolve) => {
114
+ const channel = 'sca';
115
+ const postMessageClient = new PostMessageClient({
116
+ channel,
117
+ target: this.headless,
118
+ });
119
+ let resolved = false;
120
+ postMessageClient.setEventListeners({
121
+ [BridgeEvent.THREE_D_SECURE_ENABLED]: (data) => {
122
+ const enabled = typeof data === 'boolean' ? data : false;
123
+ if (!resolved) {
124
+ this.reportThreeDSecureFetched(data, paymentIntent);
125
+ resolved = true;
126
+ resolve(enabled);
127
+ }
128
+ },
129
+ }, { once: true });
130
+ const message = {
131
+ channel,
132
+ subject: 'fzi.is-enabled-three-d-secure-req',
133
+ data: {
134
+ merchant: this.fzConfig.username,
135
+ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
136
+ },
137
+ };
138
+ postMessageClient.send(message);
139
+ window.setTimeout(() => {
107
140
  if (!resolved) {
108
- this.reportThreeDSecureFetched(data, paymentIntent);
141
+ this.reportRequestThreedsEnabledTimeout(paymentIntent);
109
142
  resolved = true;
110
- resolve(enabled);
143
+ resolve(false);
111
144
  }
112
- },
145
+ }, timeout);
113
146
  });
114
- const message = {
115
- channel,
116
- subject: 'fzi.is-enabled-three-d-secure-req',
117
- data: {
118
- merchant: this.fzConfig.username,
119
- access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
120
- },
121
- };
122
- postMessageClient.send(message);
123
- window.setTimeout(() => {
124
- if (!resolved) {
125
- this.reportRequestThreedsEnabledTimeout(paymentIntent);
126
- resolved = true;
127
- resolve(false);
128
- }
129
- }, timeout);
130
147
  });
131
148
  }
132
149
  verifyCard(params) {
133
150
  return __awaiter(this, void 0, void 0, function* () {
134
151
  var _a, _b;
135
- if (!this.threeDSecureListenersBound) {
136
- this.setThreeDSecureListeners();
137
- }
152
+ console.log('verifyCard');
138
153
  const valid = validateVerifyCardParams(params);
139
154
  if (!valid) {
140
155
  emit(PublicEvent.VALIDATION_ERROR, {
@@ -143,14 +158,15 @@ export default class FatZebra {
143
158
  });
144
159
  return;
145
160
  }
146
- const threeDSEnabled = yield this.requestThreeDSEnabled(3000, params.paymentIntent);
161
+ setTransactionReference(params.paymentIntent.payment.reference);
162
+ yield this.authReady;
147
163
  switch (params.paymentMethod.type) {
148
164
  case PaymentMethodType.CARD: {
149
165
  console.log('Verify card (new card)');
150
166
  const card = params.paymentMethod.data;
151
167
  this.cardDidTokenize((data) => __awaiter(this, void 0, void 0, function* () {
152
168
  var _a, _b;
153
- if (threeDSEnabled) {
169
+ if (this.threeDSecure && this.isThreeDSecureEnabled) {
154
170
  this.threeDSecure.run({
155
171
  paymentIntent: params.paymentIntent,
156
172
  cardToken: data.token,
@@ -163,6 +179,7 @@ export default class FatZebra {
163
179
  else {
164
180
  const bin = card.number.substr(0, 6);
165
181
  this.sca.run({
182
+ source: 'verifyCard',
166
183
  cardToken: data.token,
167
184
  customer: params.customer,
168
185
  paymentIntent: params.paymentIntent,
@@ -177,7 +194,7 @@ export default class FatZebra {
177
194
  case PaymentMethodType.CARD_ON_FILE: {
178
195
  console.log('Verify card (card on file)');
179
196
  const cardToken = params.paymentMethod.data.token;
180
- if (threeDSEnabled) {
197
+ if (this.threeDSecure && this.isThreeDSecureEnabled) {
181
198
  this.threeDSecure.run({
182
199
  paymentIntent: params.paymentIntent,
183
200
  cardToken,
@@ -192,6 +209,7 @@ export default class FatZebra {
192
209
  card_token: cardToken,
193
210
  })).data.bin;
194
211
  this.sca.run({
212
+ source: 'verifyCard',
195
213
  cardToken,
196
214
  customer: params.customer,
197
215
  paymentIntent: params.paymentIntent,
@@ -204,21 +222,7 @@ export default class FatZebra {
204
222
  }
205
223
  });
206
224
  }
207
- setThreeDSecureListeners() {
208
- console.log('setThreeDSecureListeners');
209
- if (this.threeDSecureListenersBound)
210
- return;
211
- const channel = 'sca';
212
- const postMessageClient = new PostMessageClient({
213
- channel,
214
- target: this.headless,
215
- });
216
- const handlers = this.threeDSecure.messageHandlers();
217
- postMessageClient.setEventListeners(handlers);
218
- this.threeDSecureListenersBound = true;
219
- }
220
225
  renderPaymentsPage(params) {
221
- var _a;
222
226
  console.log('renderPaymentsPage');
223
227
  const valid = validateHppLoadParams(params);
224
228
  if (!valid) {
@@ -228,20 +232,25 @@ export default class FatZebra {
228
232
  });
229
233
  return;
230
234
  }
231
- if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
232
- window.HPP.destroy();
233
- }
234
- window.HPP = new Hpp({
235
- version: params.version,
236
- paymentIntent: params.paymentIntent,
237
- customer: params.customer,
238
- username: this.fzConfig.username,
239
- sca: this.sca,
240
- test: this.fzConfig.test,
241
- threeDSecure: this.threeDSecure,
242
- requestThreeDSEnabled: () => this.requestThreeDSEnabled(1000, params.paymentIntent),
235
+ // chaining here to avoid making renderPaymentsPage async
236
+ // this is ugly but should only be temporary while we need to call requestThreeDSecureEnabled to fetch the flag
237
+ this.authReady.then(() => {
238
+ var _a;
239
+ if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
240
+ window.HPP.destroy();
241
+ }
242
+ window.HPP = new Hpp({
243
+ version: params.version,
244
+ paymentIntent: params.paymentIntent,
245
+ customer: params.customer,
246
+ username: this.fzConfig.username,
247
+ sca: this.sca,
248
+ test: this.fzConfig.test,
249
+ threeDSecure: this.threeDSecure,
250
+ isThreeDSecureEnabled: this.isThreeDSecureEnabled,
251
+ });
252
+ window.HPP.load(params);
243
253
  });
244
- window.HPP.load(params);
245
254
  }
246
255
  renderApplePayButton(params) {
247
256
  const valid = validateApplePayLoadParams(params);
@@ -279,14 +288,24 @@ export default class FatZebra {
279
288
  });
280
289
  window.HPP.load(params);
281
290
  }
282
- reportThreeDSecureFetchedOnInit(data) {
283
- console.log("three_d_secure fetched on init", data);
291
+ setThreeDSecureListeners() {
292
+ console.log('setThreeDSecureListeners');
293
+ if (this.threeDSecureListenersBound)
294
+ return;
295
+ const channel = 'sca';
296
+ const postMessageClient = new PostMessageClient({
297
+ channel,
298
+ target: this.headless,
299
+ });
300
+ const handlers = this.threeDSecure.messageHandlers();
301
+ postMessageClient.setEventListeners(handlers);
302
+ this.threeDSecureListenersBound = true;
284
303
  }
285
304
  reportThreeDSecureFetched(data, paymentIntent) {
286
- console.log("three_d_secure fetched", data);
305
+ console.log('three_d_secure fetched', data);
287
306
  }
288
307
  reportRequestThreedsEnabledTimeout(paymentIntent) {
289
- console.log("3DS enabled check timed out");
308
+ console.log('3DS enabled check timed out');
290
309
  }
291
310
  checkout() {
292
311
  window.HPP.purchase();
@@ -304,15 +323,14 @@ export default class FatZebra {
304
323
  __decorate([
305
324
  logMethod({
306
325
  mapArgs: (args) => {
307
- const params = args[0];
308
326
  return [
309
327
  {
310
- payment_intent: params === null || params === void 0 ? void 0 : params.paymentIntent
328
+ payment_intent: args[1]
311
329
  },
312
330
  ];
313
331
  },
314
332
  })
315
- ], FatZebra.prototype, "requestThreeDSEnabled", null);
333
+ ], FatZebra.prototype, "requestThreeDSecureEnabled", null);
316
334
  __decorate([
317
335
  logMethod({
318
336
  mapArgs: (args) => {
@@ -323,6 +341,7 @@ __decorate([
323
341
  merchant_username: window.MerchantUsername,
324
342
  payment_intent: params === null || params === void 0 ? void 0 : params.paymentIntent,
325
343
  payment_method: (_a = params === null || params === void 0 ? void 0 : params.paymentMethod) === null || _a === void 0 ? void 0 : _a.type,
344
+ options: params === null || params === void 0 ? void 0 : params.options,
326
345
  },
327
346
  ];
328
347
  },
@@ -335,31 +354,23 @@ __decorate([
335
354
  return [
336
355
  {
337
356
  payment_intent: params.paymentIntent,
338
- version: params.version
357
+ version: params.version,
358
+ options: params.options
339
359
  },
340
360
  ];
341
361
  },
342
362
  })
343
363
  ], FatZebra.prototype, "renderPaymentsPage", null);
344
364
  __decorate([
345
- logMethod({
346
- mapArgs: (args) => {
347
- const data = args[0];
348
- return [
349
- {
350
- data
351
- },
352
- ];
353
- },
354
- })
355
- ], FatZebra.prototype, "reportThreeDSecureFetchedOnInit", null);
365
+ logMethod()
366
+ ], FatZebra.prototype, "renderClickToPay", null);
356
367
  __decorate([
357
368
  logMethod({
358
369
  mapArgs: (args) => {
359
- const data = args[0];
360
370
  return [
361
371
  {
362
- data
372
+ data: args[0],
373
+ payment_intent: args[1]
363
374
  },
364
375
  ];
365
376
  },
@@ -368,13 +379,15 @@ __decorate([
368
379
  __decorate([
369
380
  logMethod({
370
381
  mapArgs: (args) => {
371
- const data = args[0];
372
382
  return [
373
383
  {
374
- data
384
+ payment_intent: args[0]
375
385
  },
376
386
  ];
377
387
  },
378
388
  })
379
389
  ], FatZebra.prototype, "reportRequestThreedsEnabledTimeout", null);
390
+ __decorate([
391
+ logMethod()
392
+ ], FatZebra.prototype, "checkout", null);
380
393
  export { FatZebra, };
@@ -46,7 +46,7 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
46
46
  cardToken: data.token,
47
47
  merchantUsername: config.username,
48
48
  test: config.environment !== Environment.production,
49
- tokenizeOnly: config.options.tokenize_only,
49
+ tokenizeOnly: true,
50
50
  iframe: iframe
51
51
  });
52
52
  return;
@@ -3,7 +3,9 @@ import { EventCallback, Customer, PaymentIntent } from '../shared/types';
3
3
  import { CardinalManager } from './cardinal';
4
4
  import GatewayClient from '../shared/api-gateway-client';
5
5
  import { Environment } from "../shared/env";
6
+ type ScaSource = 'verifyCard' | 'hpp';
6
7
  export interface ScaRunProps {
8
+ source?: ScaSource;
7
9
  cardToken: string;
8
10
  customer?: Customer;
9
11
  paymentIntent: PaymentIntent;
@@ -39,6 +41,7 @@ declare class Sca {
39
41
  private successCallback;
40
42
  private failureCallback;
41
43
  private environmentConfig;
44
+ private source;
42
45
  constructor({ gatewayClient, successCallback, failureCallback }: ScaConfig);
43
46
  loadScript(): void;
44
47
  get cardinal(): CardinalManager;
package/dist/sca/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
1
7
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
8
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
9
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -13,6 +19,7 @@ import { CardinalManager, } from './cardinal';
13
19
  import { emit, } from '../shared/event-manager';
14
20
  import env, { Environment } from "../shared/env";
15
21
  import { getEnrollmentResult, getValidationResult, threedsResponseData } from "./utility";
22
+ import { logMethod } from '../logging/logMethod';
16
23
  class Sca {
17
24
  constructor({ gatewayClient, successCallback, failureCallback }) {
18
25
  this.gatewayClient = gatewayClient;
@@ -38,27 +45,28 @@ class Sca {
38
45
  }
39
46
  reportFailure(message, data) {
40
47
  if (this.failureCallback) {
41
- const event = new CustomEvent(PublicEvent.SCA_ERROR, { detail: { errors: [message], data: data } });
48
+ const event = new CustomEvent(PublicEvent.SCA_ERROR, { detail: { errors: [message], data: Object.assign(Object.assign({}, data), { source: this.source }) } });
42
49
  this.failureCallback(event);
43
50
  }
44
51
  else {
45
- emit(PublicEvent.SCA_ERROR, { errors: [message], data: data });
52
+ emit(PublicEvent.SCA_ERROR, { errors: [message], data: Object.assign(Object.assign({}, data), { source: this.source }) });
46
53
  }
47
54
  console.log(message);
48
55
  }
49
56
  reportSuccess(message, data) {
50
57
  if (this.successCallback) {
51
- const event = new CustomEvent(PublicEvent.SCA_SUCCESS, { detail: data });
58
+ const event = new CustomEvent(PublicEvent.SCA_SUCCESS, { detail: { data: Object.assign(Object.assign({}, data), { source: this.source }) } });
52
59
  this.successCallback(event);
53
60
  }
54
61
  else {
55
- emit(PublicEvent.SCA_SUCCESS, { message, data });
62
+ emit(PublicEvent.SCA_SUCCESS, { message, data: Object.assign(Object.assign({}, data), { source: this.source }) });
56
63
  }
57
64
  console.log(message);
58
65
  }
59
66
  run(config) {
60
67
  return __awaiter(this, void 0, void 0, function* () {
61
68
  console.log('Running 3DS (SCA)');
69
+ this.source = config.source;
62
70
  try {
63
71
  if (!this._cardinal) {
64
72
  this._cardinal = new CardinalManager();
@@ -221,4 +229,43 @@ class Sca {
221
229
  }
222
230
  }
223
231
  }
232
+ __decorate([
233
+ logMethod({
234
+ mapArgs: (args) => {
235
+ return [
236
+ {
237
+ message: args[0],
238
+ data: args[1],
239
+ },
240
+ ];
241
+ },
242
+ })
243
+ ], Sca.prototype, "reportFailure", null);
244
+ __decorate([
245
+ logMethod({
246
+ mapArgs: (args) => {
247
+ return [
248
+ {
249
+ message: args[0],
250
+ data: args[1],
251
+ },
252
+ ];
253
+ },
254
+ })
255
+ ], Sca.prototype, "reportSuccess", null);
256
+ __decorate([
257
+ logMethod({
258
+ mapArgs: (args) => {
259
+ const params = args[0];
260
+ return [
261
+ {
262
+ source: params.source,
263
+ payment_intent: params.paymentIntent,
264
+ card_token: params.cardToken,
265
+ challenge_window_size: params.challengeWindowSize,
266
+ },
267
+ ];
268
+ },
269
+ })
270
+ ], Sca.prototype, "run", null);
224
271
  export default Sca;
@@ -42,9 +42,13 @@ declare class PostMessageClient {
42
42
  private fzEnv;
43
43
  private target;
44
44
  private domain;
45
+ private messageListener;
45
46
  constructor(config: PostMessageClientConfig);
46
- setEventListeners(handlers: EventHandlers): void;
47
+ setEventListeners(handlers: EventHandlers, options?: {
48
+ once?: boolean;
49
+ }): void;
47
50
  setEventListenersLegacy(handlers: EventHandlers): void;
51
+ removeEventListeners(): void;
48
52
  send(message: PostMessage | PostMessageLegacy): void;
49
53
  }
50
54
  export { PostMessageClient, };
@@ -10,14 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import env, { Environment } from "./env";
11
11
  class PostMessageClient {
12
12
  constructor(config) {
13
+ this.messageListener = null;
13
14
  this.channel = config.channel;
14
15
  this.fzEnv = config.environment || process.env.API_ENV;
15
16
  this.domain = env[this.fzEnv].payNowUrl;
16
17
  this.target = config.target;
17
18
  }
18
19
  // Handle event messages that conform to PostMessage format.
19
- setEventListeners(handlers) {
20
- window.addEventListener("message", (event) => __awaiter(this, void 0, void 0, function* () {
20
+ setEventListeners(handlers, options = {}) {
21
+ this.messageListener = (event) => __awaiter(this, void 0, void 0, function* () {
21
22
  const validationEnabled = ![Environment.test, Environment.local, Environment.development].includes(this.fzEnv);
22
23
  const isChannelValid = event.data.channel === this.channel;
23
24
  const isOriginValid = event.origin === this.domain;
@@ -29,6 +30,14 @@ class PostMessageClient {
29
30
  const subject = message.subject;
30
31
  const handler = handlers[subject];
31
32
  if (handler) {
33
+ // Intentionally not using addEventListener's built-in { once } option.
34
+ // That would remove the listener on the first message event of any kind,
35
+ // so an unrelated message arriving before the expected subject would silently consume the listener
36
+ // and cause a timeout. Instead, we remove only after a matching subject is found.
37
+ if (options.once && this.messageListener) {
38
+ console.log(subject, 'Removing message listener after first use');
39
+ window.removeEventListener('message', this.messageListener);
40
+ }
32
41
  handler(message.data);
33
42
  }
34
43
  else {
@@ -36,7 +45,8 @@ class PostMessageClient {
36
45
  // not to handle certain messages posted from child frame.
37
46
  console.log(`[WARNING] No handler registered for subject ${subject}, message ${JSON.stringify(message)}`);
38
47
  }
39
- }));
48
+ });
49
+ window.addEventListener("message", this.messageListener);
40
50
  }
41
51
  // Handle event messages that do not conform to PostMessage format.
42
52
  setEventListenersLegacy(handlers) {
@@ -59,6 +69,12 @@ class PostMessageClient {
59
69
  }
60
70
  });
61
71
  }
72
+ removeEventListeners() {
73
+ if (this.messageListener) {
74
+ window.removeEventListener("message", this.messageListener);
75
+ this.messageListener = null;
76
+ }
77
+ }
62
78
  send(message) {
63
79
  this.target.contentWindow.postMessage(message, this.domain);
64
80
  }
@@ -9,6 +9,15 @@ interface ThreeDSecureConfig {
9
9
  bridge: HTMLIFrameElement;
10
10
  iframe?: HTMLIFrameElement;
11
11
  }
12
+ interface ThreeDSecureRunProps {
13
+ paymentIntent: PaymentIntent;
14
+ cardToken: string;
15
+ merchantUsername: string;
16
+ challengeWindowSize?: ChallengeWindowSize;
17
+ tokenizeOnly?: boolean;
18
+ iframe?: HTMLIFrameElement;
19
+ test: boolean;
20
+ }
12
21
  declare class ThreeDSecure {
13
22
  private headlessBridge;
14
23
  private cybersourceReferenceId;
@@ -23,15 +32,7 @@ declare class ThreeDSecure {
23
32
  private tokenizeOnly;
24
33
  private iframe?;
25
34
  constructor({ successCallback, failureCallback, environment, bridge }: ThreeDSecureConfig);
26
- run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: {
27
- paymentIntent: PaymentIntent;
28
- cardToken: string;
29
- merchantUsername: string;
30
- challengeWindowSize?: ChallengeWindowSize;
31
- test: boolean;
32
- tokenizeOnly?: boolean;
33
- iframe?: HTMLIFrameElement;
34
- }): void;
35
+ run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: ThreeDSecureRunProps): void;
35
36
  setupResponse(data: DeviceDataCollectionMessage): void;
36
37
  messageHandlers(): {
37
38
  [key: string]: (data: any) => void;
@@ -198,10 +198,43 @@ class ThreeDSecure {
198
198
  }
199
199
  }
200
200
  __decorate([
201
- logMethod()
201
+ logMethod({
202
+ mapArgs: (args) => {
203
+ const params = args[0];
204
+ return [
205
+ {
206
+ payment_intent: params.paymentIntent,
207
+ card_token: params.cardToken,
208
+ challenge_window_size: params.challengeWindowSize,
209
+ tokenize_only: params.tokenizeOnly,
210
+ },
211
+ ];
212
+ },
213
+ })
214
+ ], ThreeDSecure.prototype, "run", null);
215
+ __decorate([
216
+ logMethod({
217
+ mapArgs: (args) => {
218
+ return [
219
+ {
220
+ message: args[0],
221
+ data: args[1],
222
+ },
223
+ ];
224
+ },
225
+ })
202
226
  ], ThreeDSecure.prototype, "reportSuccess", null);
203
227
  __decorate([
204
- logMethod()
228
+ logMethod({
229
+ mapArgs: (args) => {
230
+ return [
231
+ {
232
+ message: args[0],
233
+ data: args[1],
234
+ },
235
+ ];
236
+ },
237
+ })
205
238
  ], ThreeDSecure.prototype, "reportFailure", null);
206
239
  __decorate([
207
240
  logMethod()
@@ -1,5 +1,6 @@
1
1
  import { toFzSli } from "../../sca/eci-mappings";
2
2
  const threeDResponseData = (response) => {
3
+ var _a;
3
4
  return {
4
5
  // CAVV: Visa & Amex only
5
6
  // AAV: Mastercard only, known as UCAF
@@ -8,7 +9,7 @@ const threeDResponseData = (response) => {
8
9
  sli: toFzSli(response.eci),
9
10
  eci: response.eci,
10
11
  xid: response.xid,
11
- ver: response === null || response === void 0 ? void 0 : response.veres,
12
+ ver: (_a = response === null || response === void 0 ? void 0 : response.veres) !== null && _a !== void 0 ? _a : null,
12
13
  directoryServerTxnId: response.directory_server_txn_id,
13
14
  threedsVersion: response.threeds_version,
14
15
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fat-zebra/sdk",
3
- "version": "2.0.1-beta.9",
3
+ "version": "2.0.2-beta.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {