@fat-zebra/sdk 2.0.1-beta.11 → 2.0.1-beta.13

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?: {
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,34 @@ 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
+ if (!this.crossFrameListenersBound) {
56
+ this.setCrossFramesEventListeners();
57
+ this.crossFrameListenersBound = true;
58
+ }
59
+ if (this.headlessLoaded && this.iframeLoaded) {
60
+ if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
61
+ this.setPublicEventListeners();
62
+ this.publicEventListenersBound = true;
64
63
  }
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);
64
+ emit(PublicEvent.HPP_READY);
65
+ }
66
+ else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
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;
74
72
  }
75
- });
73
+ emit(PublicEvent.HPP_READY);
74
+ }
76
75
  }
77
76
  load(config) {
78
77
  var _a;
@@ -136,9 +135,12 @@ class Hpp {
136
135
  return queryString ? `${base}?${searchParams.toString()}` : `${base}`;
137
136
  }
138
137
  setCrossFramesEventListeners() {
138
+ console.log('setCrossFramesEventListeners');
139
139
  const handlers = {};
140
140
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
141
141
  var _a;
142
+ if (data.source === 'verifyCard')
143
+ return;
142
144
  if (data.errors) {
143
145
  emit(PublicEvent.TOKENIZATION_ERROR, {
144
146
  message: 'Card tokenization failed.',
@@ -172,6 +174,7 @@ class Hpp {
172
174
  return; // do not continue execution to old 3DS
173
175
  }
174
176
  this.sca.run({
177
+ source: 'hpp',
175
178
  cardToken: data.token,
176
179
  customer: this.customer,
177
180
  paymentIntent: this.paymentIntent,
@@ -233,11 +236,14 @@ class Hpp {
233
236
  this.postMessageClient.setEventListeners(handlers);
234
237
  }
235
238
  setPublicEventListeners() {
239
+ console.log('setPublicEventListeners');
236
240
  this.scaHandler = (event) => {
241
+ if (event.detail.data.source === 'verifyCard')
242
+ return;
237
243
  if (this.hppOptions.tokenizeOnly)
238
244
  return;
239
245
  const threedsData = event.detail.data;
240
- const extra = util.toObjectWithSnakeCaseKeys(threedsData);
246
+ const _a = util.toObjectWithSnakeCaseKeys(threedsData), { source } = _a, extra = __rest(_a, ["source"]);
241
247
  this.createPurchase(extra);
242
248
  };
243
249
  on(PublicEvent.SCA_SUCCESS, this.scaHandler);
@@ -247,8 +253,13 @@ class Hpp {
247
253
  off(PublicEvent.SCA_SUCCESS, this.scaHandler);
248
254
  this.publicEventListenersBound = false;
249
255
  }
256
+ if (this.crossFrameListenersBound) {
257
+ this.postMessageClient.removeEventListeners();
258
+ this.crossFrameListenersBound = false;
259
+ }
250
260
  }
251
261
  createPurchase(extra = null) {
262
+ console.log('createPurchase');
252
263
  const message = {
253
264
  channel: 'sca',
254
265
  subject: BridgeEvent.CREATE_PAYMENT_REQUEST,
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;
33
34
  private bridgeReady;
35
+ private authReady;
34
36
  constructor(config: FZConfig);
37
+ private setAuthImpl;
35
38
  tokenizeCard(card: Card): void;
36
39
  cardDidTokenize(callback: (data: any) => void): void;
37
- private requestThreeDSEnabled;
40
+ private requestThreeDSecureEnabled;
38
41
  verifyCard(params: VerifyCardParams): Promise<void>;
39
- setThreeDSecureListeners(): void;
40
42
  renderPaymentsPage(params: HppLoadParams): void;
41
43
  renderApplePayButton(params: ApplePayParams): void;
42
44
  renderClickToPay(params: HppClickToPayParams): 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
@@ -30,7 +30,10 @@ 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,40 +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
- // bridgeReady is a single promise created once.
52
- // After it resolves (bridge loaded), every subsequent "await this.bridgeReady"
53
- // returns instantly — there's no re-evaluation.
54
- // So for a SPA where the bridge is already loaded, there's zero overhead.
55
46
  if (isExisting) {
56
- console.log('headless exists');
57
47
  this.bridgeReady = Promise.resolve();
58
- this.setThreeDSecureListeners();
59
48
  }
60
49
  else {
61
50
  this.bridgeReady = new Promise((resolve) => {
62
- this.headless.addEventListener('load', () => {
63
- console.log('headless loaded');
64
- this.setThreeDSecureListeners();
65
- resolve();
66
- });
51
+ this.headless.addEventListener('load', () => resolve());
67
52
  });
68
53
  }
54
+ this.authReady = this.setAuthImpl();
69
55
  const message = {
70
56
  channel: 'sca',
71
57
  subject: BridgeEvent.READY,
72
58
  data: {},
73
59
  };
74
- 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
+ });
75
81
  }
76
82
  tokenizeCard(card) {
77
83
  const channel = 'sca';
@@ -79,6 +85,7 @@ export default class FatZebra {
79
85
  channel,
80
86
  subject: BridgeEvent.TOKENIZE_CARD_REQUEST,
81
87
  data: {
88
+ source: 'verifyCard',
82
89
  access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
83
90
  card_holder: card.holder,
84
91
  card_number: card.number,
@@ -98,20 +105,11 @@ export default class FatZebra {
98
105
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
99
106
  callback(data);
100
107
  };
101
- postMessageClient.setEventListeners(handlers);
108
+ postMessageClient.setEventListeners(handlers, { once: true });
102
109
  }
103
- requestThreeDSEnabled(timeout, paymentIntent) {
110
+ requestThreeDSecureEnabled(timeout, paymentIntent) {
104
111
  return __awaiter(this, void 0, void 0, function* () {
105
112
  console.log('requestThreeDSEnabled');
106
- // If the bridge loads in time, bridgeReady wins and we can continue requesting the flag.
107
- // If not, the timeout resolves the race and we fall through
108
- // — the postMessage is sent to an unready bridge, the response never arrives,
109
- // and the existing window.setTimeout at the bottom fires and resolves false.
110
- // The total worst-case wait is still bounded by timeout.
111
- yield Promise.race([
112
- this.bridgeReady,
113
- new Promise((resolve) => window.setTimeout(resolve, timeout)),
114
- ]);
115
113
  return new Promise((resolve) => {
116
114
  const channel = 'sca';
117
115
  const postMessageClient = new PostMessageClient({
@@ -128,7 +126,7 @@ export default class FatZebra {
128
126
  resolve(enabled);
129
127
  }
130
128
  },
131
- });
129
+ }, { once: true });
132
130
  const message = {
133
131
  channel,
134
132
  subject: 'fzi.is-enabled-three-d-secure-req',
@@ -160,14 +158,14 @@ export default class FatZebra {
160
158
  });
161
159
  return;
162
160
  }
163
- const threeDSEnabled = yield this.requestThreeDSEnabled(1000, params.paymentIntent);
161
+ yield this.authReady;
164
162
  switch (params.paymentMethod.type) {
165
163
  case PaymentMethodType.CARD: {
166
164
  console.log('Verify card (new card)');
167
165
  const card = params.paymentMethod.data;
168
166
  this.cardDidTokenize((data) => __awaiter(this, void 0, void 0, function* () {
169
167
  var _a, _b;
170
- if (threeDSEnabled) {
168
+ if (this.threeDSecure && this.isThreeDSecureEnabled) {
171
169
  this.threeDSecure.run({
172
170
  paymentIntent: params.paymentIntent,
173
171
  cardToken: data.token,
@@ -180,6 +178,7 @@ export default class FatZebra {
180
178
  else {
181
179
  const bin = card.number.substr(0, 6);
182
180
  this.sca.run({
181
+ source: 'verifyCard',
183
182
  cardToken: data.token,
184
183
  customer: params.customer,
185
184
  paymentIntent: params.paymentIntent,
@@ -194,7 +193,7 @@ export default class FatZebra {
194
193
  case PaymentMethodType.CARD_ON_FILE: {
195
194
  console.log('Verify card (card on file)');
196
195
  const cardToken = params.paymentMethod.data.token;
197
- if (threeDSEnabled) {
196
+ if (this.threeDSecure && this.isThreeDSecureEnabled) {
198
197
  this.threeDSecure.run({
199
198
  paymentIntent: params.paymentIntent,
200
199
  cardToken,
@@ -209,6 +208,7 @@ export default class FatZebra {
209
208
  card_token: cardToken,
210
209
  })).data.bin;
211
210
  this.sca.run({
211
+ source: 'verifyCard',
212
212
  cardToken,
213
213
  customer: params.customer,
214
214
  paymentIntent: params.paymentIntent,
@@ -221,21 +221,7 @@ export default class FatZebra {
221
221
  }
222
222
  });
223
223
  }
224
- setThreeDSecureListeners() {
225
- console.log('setThreeDSecureListeners');
226
- if (this.threeDSecureListenersBound)
227
- return;
228
- const channel = 'sca';
229
- const postMessageClient = new PostMessageClient({
230
- channel,
231
- target: this.headless,
232
- });
233
- const handlers = this.threeDSecure.messageHandlers();
234
- postMessageClient.setEventListeners(handlers);
235
- this.threeDSecureListenersBound = true;
236
- }
237
224
  renderPaymentsPage(params) {
238
- var _a;
239
225
  console.log('renderPaymentsPage');
240
226
  const valid = validateHppLoadParams(params);
241
227
  if (!valid) {
@@ -245,20 +231,25 @@ export default class FatZebra {
245
231
  });
246
232
  return;
247
233
  }
248
- if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
249
- window.HPP.destroy();
250
- }
251
- window.HPP = new Hpp({
252
- version: params.version,
253
- paymentIntent: params.paymentIntent,
254
- customer: params.customer,
255
- username: this.fzConfig.username,
256
- sca: this.sca,
257
- test: this.fzConfig.test,
258
- threeDSecure: this.threeDSecure,
259
- requestThreeDSEnabled: () => this.requestThreeDSEnabled(1000, params.paymentIntent),
234
+ // chaining here to avoid making renderPaymentsPage async
235
+ // this is ugly but should only be temporary while we need to call requestThreeDSecureEnabled to fetch the flag
236
+ this.authReady.then(() => {
237
+ var _a;
238
+ if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
239
+ window.HPP.destroy();
240
+ }
241
+ window.HPP = new Hpp({
242
+ version: params.version,
243
+ paymentIntent: params.paymentIntent,
244
+ customer: params.customer,
245
+ username: this.fzConfig.username,
246
+ sca: this.sca,
247
+ test: this.fzConfig.test,
248
+ threeDSecure: this.threeDSecure,
249
+ isThreeDSecureEnabled: this.isThreeDSecureEnabled,
250
+ });
251
+ window.HPP.load(params);
260
252
  });
261
- window.HPP.load(params);
262
253
  }
263
254
  renderApplePayButton(params) {
264
255
  const valid = validateApplePayLoadParams(params);
@@ -296,11 +287,24 @@ export default class FatZebra {
296
287
  });
297
288
  window.HPP.load(params);
298
289
  }
290
+ setThreeDSecureListeners() {
291
+ console.log('setThreeDSecureListeners');
292
+ if (this.threeDSecureListenersBound)
293
+ return;
294
+ const channel = 'sca';
295
+ const postMessageClient = new PostMessageClient({
296
+ channel,
297
+ target: this.headless,
298
+ });
299
+ const handlers = this.threeDSecure.messageHandlers();
300
+ postMessageClient.setEventListeners(handlers);
301
+ this.threeDSecureListenersBound = true;
302
+ }
299
303
  reportThreeDSecureFetched(data, paymentIntent) {
300
- console.log("three_d_secure fetched", data);
304
+ console.log('three_d_secure fetched', data);
301
305
  }
302
306
  reportRequestThreedsEnabledTimeout(paymentIntent) {
303
- console.log("3DS enabled check timed out");
307
+ console.log('3DS enabled check timed out');
304
308
  }
305
309
  checkout() {
306
310
  window.HPP.purchase();
@@ -325,7 +329,7 @@ __decorate([
325
329
  ];
326
330
  },
327
331
  })
328
- ], FatZebra.prototype, "requestThreeDSEnabled", null);
332
+ ], FatZebra.prototype, "requestThreeDSecureEnabled", null);
329
333
  __decorate([
330
334
  logMethod({
331
335
  mapArgs: (args) => {
@@ -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
@@ -45,27 +45,28 @@ class Sca {
45
45
  }
46
46
  reportFailure(message, data) {
47
47
  if (this.failureCallback) {
48
- 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 }) } });
49
49
  this.failureCallback(event);
50
50
  }
51
51
  else {
52
- emit(PublicEvent.SCA_ERROR, { errors: [message], data: data });
52
+ emit(PublicEvent.SCA_ERROR, { errors: [message], data: Object.assign(Object.assign({}, data), { source: this.source }) });
53
53
  }
54
54
  console.log(message);
55
55
  }
56
56
  reportSuccess(message, data) {
57
57
  if (this.successCallback) {
58
- 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 }) } });
59
59
  this.successCallback(event);
60
60
  }
61
61
  else {
62
- emit(PublicEvent.SCA_SUCCESS, { message, data });
62
+ emit(PublicEvent.SCA_SUCCESS, { message, data: Object.assign(Object.assign({}, data), { source: this.source }) });
63
63
  }
64
64
  console.log(message);
65
65
  }
66
66
  run(config) {
67
67
  return __awaiter(this, void 0, void 0, function* () {
68
68
  console.log('Running 3DS (SCA)');
69
+ this.source = config.source;
69
70
  try {
70
71
  if (!this._cardinal) {
71
72
  this._cardinal = new CardinalManager();
@@ -260,6 +261,7 @@ __decorate([
260
261
  const params = args[0];
261
262
  return [
262
263
  {
264
+ source: params.source,
263
265
  payment_intent: params.paymentIntent
264
266
  },
265
267
  ];
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fat-zebra/sdk",
3
- "version": "2.0.1-beta.11",
3
+ "version": "2.0.1-beta.13",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {