@paydock/client-sdk 1.145.0-beta → 1.148.0-beta

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.
Files changed (43) hide show
  1. package/README.md +129 -1
  2. package/bundles/index.cjs +935 -103
  3. package/bundles/index.cjs.d.ts +629 -336
  4. package/bundles/index.mjs +935 -104
  5. package/bundles/index.mjs.d.ts +629 -336
  6. package/bundles/types/api/api-base.d.ts +6 -0
  7. package/bundles/types/api/api-base.d.ts.map +1 -1
  8. package/bundles/types/api/api-charge-internal.d.ts +4 -3
  9. package/bundles/types/api/api-charge-internal.d.ts.map +1 -1
  10. package/bundles/types/canvas-3ds/canvas-3ds-event-map.d.ts +65 -0
  11. package/bundles/types/canvas-3ds/canvas-3ds-event-map.d.ts.map +1 -1
  12. package/bundles/types/canvas-3ds/canvas-3ds.d.ts +34 -5
  13. package/bundles/types/canvas-3ds/canvas-3ds.d.ts.map +1 -1
  14. package/bundles/types/canvas-3ds/index.d.ts +1 -1
  15. package/bundles/types/canvas-3ds/index.d.ts.map +1 -1
  16. package/bundles/types/canvas-3ds/services/gpayments-service.d.ts +151 -2
  17. package/bundles/types/canvas-3ds/services/gpayments-service.d.ts.map +1 -1
  18. package/bundles/types/canvas-3ds/services/standalone3ds-service.d.ts +16 -0
  19. package/bundles/types/canvas-3ds/services/standalone3ds-service.d.ts.map +1 -1
  20. package/bundles/types/components/iframe-event.d.ts +4 -3
  21. package/bundles/types/components/iframe-event.d.ts.map +1 -1
  22. package/bundles/types/components/iframe.d.ts +5 -0
  23. package/bundles/types/components/iframe.d.ts.map +1 -1
  24. package/bundles/types/components/param.d.ts +19 -0
  25. package/bundles/types/components/param.d.ts.map +1 -1
  26. package/bundles/types/index-cba.d.ts +1 -1
  27. package/bundles/types/index-cba.d.ts.map +1 -1
  28. package/bundles/types/index.d.ts +2 -2
  29. package/bundles/types/index.d.ts.map +1 -1
  30. package/bundles/types/widget/multi-widget.d.ts +19 -0
  31. package/bundles/types/widget/multi-widget.d.ts.map +1 -1
  32. package/bundles/widget.umd.js +935 -103
  33. package/bundles/widget.umd.js.d.ts +629 -336
  34. package/bundles/widget.umd.js.min.d.ts +629 -336
  35. package/bundles/widget.umd.min.js +1 -1
  36. package/docs/api-canvas3ds.md +41 -8
  37. package/docs/api-checkout-button.md +15 -0
  38. package/docs/api-ps-widget.md +15 -0
  39. package/docs/api-widget.md +15 -0
  40. package/docs/canvas3ds-examples.md +43 -1
  41. package/docs/widget-examples.md +41 -0
  42. package/package.json +20 -11
  43. package/slate.md +84 -1
package/bundles/index.mjs CHANGED
@@ -1863,7 +1863,7 @@ SDK.headerKeys = Object.freeze({
1863
1863
  version: 'x-sdk-version',
1864
1864
  type: 'x-sdk-type'
1865
1865
  });
1866
- SDK._version = 'v1.145.0-beta';
1866
+ SDK._version = 'v1.148.0-beta';
1867
1867
 
1868
1868
  var ACCESS_HEADER_NAME = {
1869
1869
  accessToken: 'x-access-token',
@@ -4719,6 +4719,15 @@ var ApiBase = /*#__PURE__*/function () {
4719
4719
  this.env.setEnv(env, alias);
4720
4720
  return this;
4721
4721
  }
4722
+ /**
4723
+ * Origin (`scheme://host[:port]`) of the API this client talks to, for the current env/alias.
4724
+ * Used to validate the `origin` of postMessages the API itself sends to the page.
4725
+ */
4726
+ }, {
4727
+ key: "getApiOrigin",
4728
+ value: function getApiOrigin() {
4729
+ return ApiBase.toOrigin(this.env.getConf().url);
4730
+ }
4722
4731
  }, {
4723
4732
  key: "requestObservable",
4724
4733
  value: function requestObservable(method, url, requestBody) {
@@ -4931,6 +4940,18 @@ var ApiBase = /*#__PURE__*/function () {
4931
4940
  environment: this.env.getEnv()
4932
4941
  };
4933
4942
  }
4943
+ }], [{
4944
+ key: "toOrigin",
4945
+ value: function toOrigin(url) {
4946
+ try {
4947
+ return new URL(url).origin;
4948
+ } catch (_a) {
4949
+ // Not a parsable URL: the returned string is not an origin and will never match a
4950
+ // MessageEvent.origin — surface the misconfiguration instead of failing silently.
4951
+ console.warn("[paydock/client-sdk] cannot derive an origin from configured URL \"".concat(url, "\""));
4952
+ return url.replace(/\/+$/, '');
4953
+ }
4954
+ }
4934
4955
  }]);
4935
4956
  }();
4936
4957
 
@@ -5008,6 +5029,7 @@ var ApiChargeInternal = /*#__PURE__*/function () {
5008
5029
  value: function walletCallback(payload) {
5009
5030
  return this.api.getClientPromise('POST', WALLET_CALLBACK_LINK).send(payload);
5010
5031
  }
5032
+ /** Two-step mode: runs the deferred Standalone 3DS authentication (AReq). Charge-token auth, like `standalone3dsHandle`. */
5011
5033
  }, {
5012
5034
  key: "standalone3dsProcess",
5013
5035
  value: function standalone3dsProcess(payload) {
@@ -5151,6 +5173,10 @@ var IFrame = /*#__PURE__*/function () {
5151
5173
  _classCallCheck(this, IFrame);
5152
5174
  this.container = container;
5153
5175
  }
5176
+ /**
5177
+ * @param options.onLoad Called on every `load` of the iframe (initial document and each
5178
+ * subsequent navigation). Attached before `src` is set so a fast load is never missed.
5179
+ */
5154
5180
  return _createClass(IFrame, [{
5155
5181
  key: "load",
5156
5182
  value: function load(link) {
@@ -5159,6 +5185,9 @@ var IFrame = /*#__PURE__*/function () {
5159
5185
  if (!this.container.isExist() || this.isExist()) return;
5160
5186
  var iFrame = document.createElement('iframe');
5161
5187
  if (options.title) iFrame.title = options.title;
5188
+ if (options.onLoad) {
5189
+ iFrame.addEventListener('load', options.onLoad);
5190
+ }
5162
5191
  if (iframeClass) iFrame.classList.add(iframeClass);
5163
5192
  // Set additional attributes before src and DOM insertion so that
5164
5193
  // Permissions-Policy (e.g. allow="payment") is in place when the
@@ -5299,14 +5328,14 @@ var IFrameEvent = /*#__PURE__*/function () {
5299
5328
  data = JSON.parse(event.data);
5300
5329
  } catch (error) {}
5301
5330
  if (!data) return;
5302
- _this.emit(data);
5331
+ _this.emit(data, event.origin);
5303
5332
  });
5304
5333
  }
5305
5334
  return _createClass(IFrameEvent, [{
5306
5335
  key: "emit",
5307
- value: function emit(data) {
5336
+ value: function emit(data, origin) {
5308
5337
  for (var key in this.listeners) {
5309
- if (this.listeners[key].event === data.event && data.widget_id === this.listeners[key].widget_id) this.listeners[key].listener.apply(this, [data]);
5338
+ if (this.listeners[key].event === data.event && data.widget_id === this.listeners[key].widget_id) this.listeners[key].listener.apply(this, [data, origin]);
5310
5339
  }
5311
5340
  }
5312
5341
  }, {
@@ -5366,6 +5395,51 @@ var IFRAME_STATUS;
5366
5395
  IFRAME_STATUS["TIMEOUT"] = "AuthTimedOut";
5367
5396
  IFRAME_STATUS["INVALID"] = "invalid_event";
5368
5397
  })(IFRAME_STATUS || (IFRAME_STATUS = {}));
5398
+ /**
5399
+ * Maps a `/process` rejection onto the error object the one-step callback delivers for the same outcome
5400
+ * (`{ error_code, error_description, gateway_specific_description, process_error_code }`), so `error`
5401
+ * carries the same payload in both flows. Absent fields are left out.
5402
+ */
5403
+ function toOutcomeError(err) {
5404
+ var _a, _b;
5405
+ if (err instanceof Error) {
5406
+ // no API envelope to map (the body was not the API's JSON): report it as unreachable, so the
5407
+ // merchant can tell this retryable case apart from a final API answer by `error_code` alone
5408
+ return {
5409
+ error_code: ERROR_CAUSE.SERVICE_UNREACHABLE,
5410
+ error_description: 'Network request failed: the service did not answer with a valid response.'
5411
+ };
5412
+ }
5413
+ var apiError = err !== null && err !== void 0 ? err : {};
5414
+ var gateway = (_b = (_a = apiError.details) === null || _a === void 0 ? void 0 : _a.messages) === null || _b === void 0 ? void 0 : _b[0];
5415
+ var fields = {
5416
+ error_code: apiError.code,
5417
+ error_description: apiError.message,
5418
+ gateway_specific_description: gateway === null || gateway === void 0 ? void 0 : gateway.gateway_specific_description,
5419
+ process_error_code: gateway === null || gateway === void 0 ? void 0 : gateway.gateway_specific_code
5420
+ };
5421
+ var outcomeError = {};
5422
+ for (var _i = 0, _Object$keys = Object.keys(fields); _i < _Object$keys.length; _i++) {
5423
+ var key = _Object$keys[_i];
5424
+ if (fields[key]) {
5425
+ outcomeError[key] = fields[key];
5426
+ }
5427
+ }
5428
+ return outcomeError;
5429
+ }
5430
+ /**
5431
+ * `true` when `/process` produced no API answer: the request never got a response (network, timeout, abort)
5432
+ * or the response body was not the API's JSON (e.g. an HTML page from a proxy in between).
5433
+ */
5434
+ function isTransportFailure(err) {
5435
+ if (err instanceof Error) {
5436
+ return true;
5437
+ }
5438
+ var code = err === null || err === void 0 ? void 0 : err.code;
5439
+ return code === ERROR_CAUSE.SERVICE_UNREACHABLE || code === ERROR_CAUSE.ABORTED;
5440
+ }
5441
+ /** Callback `process_status` of a two-step charge: fingerprint done, authentication not started. */
5442
+ var PROCESS_STATUS_DEFERRED = 'deferred';
5369
5443
  /**
5370
5444
  * Event name constants emitted during the Standalone 3DS (GPayments) flow.
5371
5445
  * Used internally by `GPaymentsService` and re-exported publicly as `CANVAS_3DS_EVENT`.
@@ -5379,6 +5453,25 @@ var GPAYMENTS_EVENT = {
5379
5453
  DECOUPLED: 'chargeAuthDecoupled',
5380
5454
  /** Challenge required — issuer demands user interaction. Payload: `Canvas3dsAuthPayload`. */
5381
5455
  CHALLENGE: 'chargeAuthChallenge',
5456
+ /**
5457
+ * Two-step mode only: fingerprint done, SDK waiting for `Canvas3ds.authenticate()`. Emitted once, before any
5458
+ * outcome event (`INFO` may precede it); never for a one-step charge. Payload: `Canvas3dsReadyPayload`.
5459
+ */
5460
+ READY: 'chargeAuthReady',
5461
+ /**
5462
+ * The challenge iframe fired its FIRST `load` after `chargeAuthChallenge` (the ACS page has painted),
5463
+ * or the `CHALLENGE_LOADED_FALLBACK_MS` safety fallback elapsed without one. Emitted exactly once per
5464
+ * challenge; never emitted for a decoupled challenge (no challenge iframe). Payload: `Canvas3dsChallengeLoadedPayload`.
5465
+ */
5466
+ CHALLENGE_LOADED: 'chargeAuthChallengeLoaded',
5467
+ /**
5468
+ * The issuer delivered the final authentication result to the 3DS Server (the shopper finished the
5469
+ * challenge, or approved a decoupled authentication) and the SDK is now obtaining the outcome. Emitted at
5470
+ * most once per authentication, always before the terminal event. Detected through the `secondary_url`
5471
+ * result monitor (`source: 'poll'`) or, when the callback message arrives first, right before the outcome
5472
+ * it carries (`source: 'callback'`). Payload: `Canvas3dsChallengeCompletedPayload`.
5473
+ */
5474
+ CHALLENGE_COMPLETED: 'chargeAuthChallengeCompleted',
5382
5475
  /** Informational signal emitted by the GPayments flow. Internal — not part of the public typed surface. */
5383
5476
  INFO: 'chargeAuthInfo',
5384
5477
  /** Error during the flow (network, parsing, etc.). Payload: `Canvas3dsErrorPayload`. */
@@ -5390,13 +5483,64 @@ var GPAYMENTS_EVENT = {
5390
5483
  * backwards-compatible internal usage.
5391
5484
  */
5392
5485
  var CANVAS_3DS_EVENT = GPAYMENTS_EVENT;
5486
+ /**
5487
+ * Upper bound on how long `chargeAuthChallengeLoaded` waits for the challenge iframe's first `load`.
5488
+ * When it elapses the event is emitted with `reason: 'timeout'` so a merchant loader is never held
5489
+ * forever; the real `load` arriving afterwards is the paint and is simply ignored.
5490
+ */
5491
+ var CHALLENGE_LOADED_FALLBACK_MS = 2500;
5492
+ /**
5493
+ * Interval of the `secondary_url` (GPayments `resultMonUrl`) poll while an ACS challenge is on screen.
5494
+ * The monitor flips to `AuthResultReady` when the issuer's RReq reaches the 3DS Server — before the ACS has
5495
+ * even returned its final page to the browser — so this poll is what makes `chargeAuthChallengeCompleted`
5496
+ * land before the shopper sees any post-submit page. GPayments recommends 2 s and leaves the interval to the
5497
+ * requestor; 1 s matches the cadence of GPayments' own monitoring frame.
5498
+ */
5499
+ var CHALLENGE_RESULT_POLL_INTERVAL_MS = 1000;
5500
+ /**
5501
+ * Interval of the `secondary_url` poll for a decoupled challenge (shopper approves out-of-band, possibly
5502
+ * minutes later; nothing to cover on screen) — the GPayments-recommended 2 s.
5503
+ */
5504
+ var DECOUPLED_RESULT_POLL_INTERVAL_MS = 2000;
5505
+ /** The result-monitor request failed at transport level (network, abort, timeout) — retried, not fatal. */
5506
+ var ResultMonitorTransportError = /*#__PURE__*/function (_Error) {
5507
+ function ResultMonitorTransportError() {
5508
+ var _this;
5509
+ _classCallCheck(this, ResultMonitorTransportError);
5510
+ _this = _callSuper(this, ResultMonitorTransportError, ['Standalone 3DS result monitor request failed']);
5511
+ _this.name = 'ResultMonitorTransportError';
5512
+ return _this;
5513
+ }
5514
+ _inherits(ResultMonitorTransportError, _Error);
5515
+ return _createClass(ResultMonitorTransportError);
5516
+ }(/*#__PURE__*/_wrapNativeSuper(Error));
5393
5517
  var GPaymentsService = /*#__PURE__*/function () {
5394
5518
  function GPaymentsService(container, api, eventEmitter) {
5519
+ var trustedOrigins = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
5395
5520
  _classCallCheck(this, GPaymentsService);
5396
5521
  this.container = container;
5397
5522
  this.api = api;
5398
5523
  this.eventEmitter = eventEmitter;
5524
+ this.trustedOrigins = trustedOrigins;
5399
5525
  this.resultRead = false;
5526
+ /** `chargeAuthChallengeLoaded` already emitted for the current challenge (by `load` or by the fallback). */
5527
+ this.challengeLoadedEmitted = false;
5528
+ /** `chargeAuthChallengeCompleted` already emitted for the current authentication (poll or callback). */
5529
+ this.challengeCompletedEmitted = false;
5530
+ /** Set once a terminal event was emitted: no lifecycle event may follow (reset when a new challenge starts). */
5531
+ this.challengeLifecycleClosed = false;
5532
+ this.challengeLoadedTimer = null;
5533
+ this.resultPollTimer = null;
5534
+ /** One-shot guard for the `chargeAuth` leg — the callback message may be delivered more than once. */
5535
+ this.authHandled = false;
5536
+ /** Two-step mode: `charge_3ds_id` of the deferred callback message; `null` until it arrives (always for one-step). */
5537
+ this.deferredCharge3dsId = null;
5538
+ /** `authenticate()` latch; consumed when the deferred message arrives, reset only after a `/process` transport failure. */
5539
+ this.authenticateRequested = false;
5540
+ /** One `/process` call per widget instance (a transport failure allows one more `authenticate()`). */
5541
+ this.authenticationStarted = false;
5542
+ /** The single `/process` retry after a transport failure has been granted; the next failure is final. */
5543
+ this.authenticationRetryUsed = false;
5400
5544
  this.iFrameEvent = new IFrameEvent(window);
5401
5545
  }
5402
5546
  return _createClass(GPaymentsService, [{
@@ -5416,6 +5560,7 @@ var GPaymentsService = /*#__PURE__*/function () {
5416
5560
  key: "initializeIFrames",
5417
5561
  value: function initializeIFrames(initializationUrl, secondaryUrl, title) {
5418
5562
  var hideAuthorization = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
5563
+ var onLoad = arguments.length > 4 ? arguments[4] : undefined;
5419
5564
  var container = this.container.getElement();
5420
5565
  if (!container) {
5421
5566
  return;
@@ -5426,7 +5571,8 @@ var GPaymentsService = /*#__PURE__*/function () {
5426
5571
  this.browserAndChallengeContainer = new Container('#paydock_authorization_iframe');
5427
5572
  this.iFrameAuthorization = new IFrame(this.browserAndChallengeContainer);
5428
5573
  this.iFrameAuthorization.load(initializationUrl, {
5429
- title: title
5574
+ title: title,
5575
+ onLoad: onLoad
5430
5576
  });
5431
5577
  if (secondaryUrl) {
5432
5578
  var divSecondaryURL = document.createElement('div');
@@ -5460,25 +5606,250 @@ var GPaymentsService = /*#__PURE__*/function () {
5460
5606
  }, {
5461
5607
  key: "setupIFrameEvents",
5462
5608
  value: function setupIFrameEvents(widgetId) {
5463
- var _this = this;
5464
- this.iFrameEvent.on(EVENT$5.CHARGE_AUTH, widgetId, function (data) {
5609
+ var _this2 = this;
5610
+ this.iFrameEvent.on(EVENT$5.CHARGE_AUTH, widgetId, function (data, origin) {
5465
5611
  if (data.status === IFRAME_STATUS.SKIPPED || data.status === IFRAME_STATUS.FINISHED) {
5612
+ // this channel is spoofable — any frame that knows the charge_3ds_id can post to it.
5613
+ // A message from an unknown sender must never terminate a live authentication: ignore it.
5614
+ if (!_this2.isTrustedOrigin(origin)) {
5615
+ return;
5616
+ }
5617
+ // one-shot: the callback message can be delivered more than once (it is posted to both
5618
+ // `parent` and `top`) — a duplicate must not re-emit events or duplicate challenge iframes
5619
+ if (_this2.authHandled) {
5620
+ return;
5621
+ }
5622
+ _this2.authHandled = true;
5466
5623
  if (data.info) {
5467
- _this.eventEmitter.emit(GPAYMENTS_EVENT.INFO, {
5624
+ _this2.eventEmitter.emit(GPAYMENTS_EVENT.INFO, {
5468
5625
  info: data.info
5469
5626
  });
5470
5627
  }
5471
- _this.performAuthentication(data);
5628
+ _this2.removeIframes();
5629
+ if (data.process_status === PROCESS_STATUS_DEFERRED) {
5630
+ // two-step: announce readiness; authenticate now only if `authenticate()` was already called
5631
+ _this2.deferredCharge3dsId = data.charge_3ds_id;
5632
+ _this2.eventEmitter.emit(GPAYMENTS_EVENT.READY, {
5633
+ charge_3ds_id: data.charge_3ds_id
5634
+ });
5635
+ if (_this2.authenticateRequested) {
5636
+ _this2.performAuthentication(data.charge_3ds_id);
5637
+ }
5638
+ } else if (typeof data.process_status === 'string') {
5639
+ // the API already ran the authentication inside the callback: no /process call needed
5640
+ _this2.handleAuthenticationOutcome({
5641
+ status: data.process_status,
5642
+ result: data.result,
5643
+ error: data.error
5644
+ }, data.charge_3ds_id);
5645
+ } else {
5646
+ // The API always runs the authentication inside the callback (PAYRAC-2480). A trusted
5647
+ // message without the outcome means an outdated API — fail, never verify via /process.
5648
+ _this2.finishChallengeLifecycle();
5649
+ _this2.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this2.parseError({
5650
+ message: 'Standalone 3DS authentication outcome missing from the callback message'
5651
+ }, data.charge_3ds_id));
5652
+ }
5472
5653
  } else if (data.status === IFRAME_STATUS.TIMEOUT || data.status === IFRAME_STATUS.INVALID) {
5473
- _this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, _this.parseHandleResponse({
5654
+ _this2.finishChallengeLifecycle();
5655
+ _this2.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, _this2.parseHandleResponse({
5474
5656
  status: data.status
5475
5657
  }, data.charge_3ds_id));
5476
5658
  }
5477
5659
  });
5478
- this.iFrameEvent.on(EVENT$5.CHARGE_AUTH_SUCCESS, widgetId, function (data) {
5479
- _this.processResult(data.charge_3ds_id);
5660
+ this.iFrameEvent.on(EVENT$5.CHARGE_AUTH_SUCCESS, widgetId, function (data, origin) {
5661
+ // the callback iframe reached Paydock with `AuthResultReady`: the issuer has answered. Announce it
5662
+ // before the outcome so merchants always see completed → terminal, whichever transport won.
5663
+ _this2.emitChallengeCompleted(data.charge_3ds_id, 'callback');
5664
+ if (_this2.hasChainedOutcome(data, origin)) {
5665
+ // the API already fetched the challenge result inside the callback: no GET /handle needed
5666
+ _this2.handleResultOutcome({
5667
+ status: data.process_status,
5668
+ result: data.result,
5669
+ error: data.error
5670
+ }, data.charge_3ds_id);
5671
+ } else {
5672
+ _this2.processResult(data.charge_3ds_id);
5673
+ }
5480
5674
  });
5481
5675
  }
5676
+ /**
5677
+ * Two-step mode: run the deferred authentication (`POST /standalone-3ds/process`). Never throws: runs now if
5678
+ * the deferred message already arrived, otherwise as soon as it does; a no-op on one-step charges, repeated
5679
+ * calls or after a terminal outcome. The outcome flows through the usual events.
5680
+ */
5681
+ }, {
5682
+ key: "authenticate",
5683
+ value: function authenticate() {
5684
+ if (this.authenticateRequested) {
5685
+ return;
5686
+ }
5687
+ this.authenticateRequested = true;
5688
+ if (this.deferredCharge3dsId !== null) {
5689
+ this.performAuthentication(this.deferredCharge3dsId);
5690
+ }
5691
+ }
5692
+ /**
5693
+ * Calls `/process` once per instance (reachable from both the deferred message and `authenticate()`). The
5694
+ * response has the callback-outcome shape, so the challenge / decoupled / result legs are shared with
5695
+ * one-step. A rejection surfaces as `error`, with the same error object shape as the one-step callback
5696
+ * (`toOutcomeError`). An API answer (stale session, rejected authentication…) is terminal. The first transport
5697
+ * failure is not: the AReq may have run with its response lost, so the latches are reset and the merchant may
5698
+ * call `authenticate()` once more — `/process` is idempotent and replays the stored outcome. A failure of that
5699
+ * retry, of any kind, is final.
5700
+ */
5701
+ }, {
5702
+ key: "performAuthentication",
5703
+ value: function performAuthentication(charge3dsId) {
5704
+ var _this3 = this;
5705
+ if (this.authenticationStarted) {
5706
+ return;
5707
+ }
5708
+ this.authenticationStarted = true;
5709
+ this.api.charge().standalone3dsProcess({
5710
+ charge_3ds_id: charge3dsId
5711
+ }).then(function (authenticationResult) {
5712
+ return _this3.handleAuthenticationOutcome(authenticationResult, charge3dsId);
5713
+ }, function (err) {
5714
+ if (isTransportFailure(err) && !_this3.authenticationRetryUsed) {
5715
+ _this3.authenticationRetryUsed = true;
5716
+ _this3.authenticateRequested = false;
5717
+ _this3.authenticationStarted = false;
5718
+ } else {
5719
+ _this3.resultRead = true;
5720
+ _this3.finishChallengeLifecycle();
5721
+ }
5722
+ _this3.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this3.parseError(toOutcomeError(err), charge3dsId));
5723
+ });
5724
+ }
5725
+ /**
5726
+ * A message carries a processed outcome only when it has `process_status` AND comes from a trusted
5727
+ * origin. Used by the result leg: an untrusted `process_status` is never acted upon — the SDK falls
5728
+ * back to `GET /handle` (still needed for decoupled challenges / polling). The authentication leg
5729
+ * ignores untrusted senders outright, before this check.
5730
+ */
5731
+ }, {
5732
+ key: "hasChainedOutcome",
5733
+ value: function hasChainedOutcome(data, origin) {
5734
+ return typeof data.process_status === 'string' && this.isTrustedOrigin(origin);
5735
+ }
5736
+ }, {
5737
+ key: "isTrustedOrigin",
5738
+ value: function isTrustedOrigin(origin) {
5739
+ // 'null' is the serialized opaque origin (e.g. a sandboxed iframe) — never trust it, even if a
5740
+ // misconfigured env URL were ever to put the literal string 'null' into the trusted list
5741
+ return typeof origin === 'string' && origin !== 'null' && this.trustedOrigins.includes(origin);
5742
+ }
5743
+ }, {
5744
+ key: "removeIframes",
5745
+ value: function removeIframes() {
5746
+ var _a, _b;
5747
+ this.clearChallengeLoadedTimer();
5748
+ (_a = this.iFrameAuthorization) === null || _a === void 0 ? void 0 : _a.remove();
5749
+ (_b = this.iFrameSecondaryUrl) === null || _b === void 0 ? void 0 : _b.remove();
5750
+ }
5751
+ }, {
5752
+ key: "clearChallengeLoadedTimer",
5753
+ value: function clearChallengeLoadedTimer() {
5754
+ if (this.challengeLoadedTimer !== null) {
5755
+ clearTimeout(this.challengeLoadedTimer);
5756
+ this.challengeLoadedTimer = null;
5757
+ }
5758
+ }
5759
+ /**
5760
+ * Challenge iframe lifecycle (`chargeAuthChallengeLoaded`).
5761
+ *
5762
+ * The challenge iframe is cross-origin, but its `load` event still fires when the ACS page finishes loading:
5763
+ * the first one means the page painted (merchants can drop their loader). A fallback timer
5764
+ * (`armChallengeLoadedFallback`) guarantees `chargeAuthChallengeLoaded` within `CHALLENGE_LOADED_FALLBACK_MS`
5765
+ * even if no `load` ever fires; a late paint after that is simply ignored. Later `load`s are NOT a usable
5766
+ * signal for "the shopper submitted": the post-submit hops are HTTP redirects and self-submitting pages whose
5767
+ * loads abort, and the final callback page posts its message before its own `load` — so the post-submit
5768
+ * moment is `chargeAuthChallengeCompleted`, driven by the `secondary_url` result monitor instead.
5769
+ *
5770
+ * Nothing is emitted once the flow reached a terminal outcome (`finishChallengeLifecycle`), and a
5771
+ * decoupled challenge (no challenge iframe) never emits `chargeAuthChallengeLoaded`.
5772
+ *
5773
+ * Resets the per-challenge state and returns the `load` handler to attach to the challenge iframe.
5774
+ */
5775
+ }, {
5776
+ key: "startChallengeLifecycle",
5777
+ value: function startChallengeLifecycle(charge3dsId) {
5778
+ var _this4 = this;
5779
+ this.clearChallengeLoadedTimer();
5780
+ this.challengeLoadedEmitted = false;
5781
+ this.challengeCompletedEmitted = false;
5782
+ this.challengeLifecycleClosed = false;
5783
+ return function () {
5784
+ var _a;
5785
+ if (_this4.challengeLifecycleClosed || _this4.challengeLoadedEmitted || !((_a = _this4.iFrameAuthorization) === null || _a === void 0 ? void 0 : _a.isExist())) {
5786
+ return;
5787
+ }
5788
+ _this4.clearChallengeLoadedTimer();
5789
+ _this4.emitChallengeLoaded(charge3dsId, 'load');
5790
+ };
5791
+ }
5792
+ /**
5793
+ * Arms the `chargeAuthChallengeLoaded` fallback — only when a challenge iframe actually exists (the
5794
+ * container may be gone, or `IFrame.load` may have no-op'd on an already-present iframe).
5795
+ */
5796
+ }, {
5797
+ key: "armChallengeLoadedFallback",
5798
+ value: function armChallengeLoadedFallback(charge3dsId) {
5799
+ var _this5 = this;
5800
+ var _a;
5801
+ if (!((_a = this.iFrameAuthorization) === null || _a === void 0 ? void 0 : _a.isExist())) {
5802
+ return;
5803
+ }
5804
+ this.challengeLoadedTimer = setTimeout(function () {
5805
+ _this5.challengeLoadedTimer = null;
5806
+ if (_this5.challengeLifecycleClosed || _this5.challengeLoadedEmitted) {
5807
+ return;
5808
+ }
5809
+ _this5.emitChallengeLoaded(charge3dsId, 'timeout');
5810
+ }, CHALLENGE_LOADED_FALLBACK_MS);
5811
+ }
5812
+ }, {
5813
+ key: "emitChallengeLoaded",
5814
+ value: function emitChallengeLoaded(charge3dsId, reason) {
5815
+ this.challengeLoadedEmitted = true;
5816
+ this.eventEmitter.emit(GPAYMENTS_EVENT.CHALLENGE_LOADED, {
5817
+ charge_3ds_id: charge3dsId,
5818
+ reason: reason
5819
+ });
5820
+ }
5821
+ /**
5822
+ * `chargeAuthChallengeCompleted` — once per authentication, never after a terminal event. Idempotent so the
5823
+ * poll and the callback message can both call it: the first transport to notice the issuer's result wins.
5824
+ */
5825
+ }, {
5826
+ key: "emitChallengeCompleted",
5827
+ value: function emitChallengeCompleted(charge3dsId, source) {
5828
+ if (this.challengeLifecycleClosed || this.challengeCompletedEmitted) {
5829
+ return;
5830
+ }
5831
+ this.challengeCompletedEmitted = true;
5832
+ this.eventEmitter.emit(GPAYMENTS_EVENT.CHALLENGE_COMPLETED, {
5833
+ charge_3ds_id: charge3dsId,
5834
+ source: source
5835
+ });
5836
+ }
5837
+ /** Call before emitting any terminal event: no lifecycle event may follow it, and the result poll stops. */
5838
+ }, {
5839
+ key: "finishChallengeLifecycle",
5840
+ value: function finishChallengeLifecycle() {
5841
+ this.clearChallengeLoadedTimer();
5842
+ this.stopResultPolling();
5843
+ this.challengeLifecycleClosed = true;
5844
+ }
5845
+ }, {
5846
+ key: "stopResultPolling",
5847
+ value: function stopResultPolling() {
5848
+ if (this.resultPollTimer !== null) {
5849
+ clearTimeout(this.resultPollTimer);
5850
+ this.resultPollTimer = null;
5851
+ }
5852
+ }
5482
5853
  }, {
5483
5854
  key: "parseResultData",
5484
5855
  value: function parseResultData(_ref2, charge3dsId) {
@@ -5512,24 +5883,49 @@ var GPaymentsService = /*#__PURE__*/function () {
5512
5883
  }, {
5513
5884
  key: "processResult",
5514
5885
  value: function processResult(charge3dsId) {
5515
- var _this2 = this;
5886
+ var _this6 = this;
5516
5887
  if (this.resultRead) {
5517
5888
  return;
5518
5889
  }
5519
5890
  this.resultRead = true;
5891
+ this.finishChallengeLifecycle();
5520
5892
  this.api.charge().standalone3dsHandle().then(function (result) {
5521
5893
  var _a;
5522
- _this2.iFrameAuthorization.remove();
5523
- (_a = _this2.iFrameSecondaryUrl) === null || _a === void 0 ? void 0 : _a.remove();
5894
+ _this6.iFrameAuthorization.remove();
5895
+ (_a = _this6.iFrameSecondaryUrl) === null || _a === void 0 ? void 0 : _a.remove();
5524
5896
  if (result.status === PROCESS_STANDALONE_3DS_STATUS.SUCCESS) {
5525
- _this2.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_SUCCESS, _this2.parseResultData(result, charge3dsId));
5897
+ _this6.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_SUCCESS, _this6.parseResultData(result, charge3dsId));
5526
5898
  } else {
5527
- _this2.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, _this2.parseResultData(result, charge3dsId));
5899
+ _this6.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, _this6.parseResultData(result, charge3dsId));
5528
5900
  }
5529
5901
  }, function (err) {
5530
- _this2.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this2.parseError(err, charge3dsId));
5902
+ _this6.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this6.parseError(err, charge3dsId));
5531
5903
  });
5532
5904
  }
5905
+ /** Final (post-challenge) outcome delivered by the API through the callback message. */
5906
+ }, {
5907
+ key: "handleResultOutcome",
5908
+ value: function handleResultOutcome(_ref4, charge3dsId) {
5909
+ var status = _ref4.status,
5910
+ error = _ref4.error;
5911
+ if (this.resultRead) {
5912
+ return;
5913
+ }
5914
+ this.resultRead = true;
5915
+ this.finishChallengeLifecycle();
5916
+ this.removeIframes();
5917
+ if (status === PROCESS_STANDALONE_3DS_STATUS.SUCCESS) {
5918
+ this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_SUCCESS, this.parseResultData({
5919
+ status: status
5920
+ }, charge3dsId));
5921
+ } else if (status === PROCESS_STANDALONE_3DS_STATUS.ERROR) {
5922
+ this.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, this.parseError(error, charge3dsId));
5923
+ } else {
5924
+ this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, this.parseResultData({
5925
+ status: status
5926
+ }, charge3dsId));
5927
+ }
5928
+ }
5533
5929
  }, {
5534
5930
  key: "externalAPI",
5535
5931
  value: function externalAPI(method, url) {
@@ -5543,60 +5939,106 @@ var GPaymentsService = /*#__PURE__*/function () {
5543
5939
  reject(error);
5544
5940
  }
5545
5941
  };
5942
+ // without these a failed request left the promise pending forever and the poll silently dead
5943
+ var fail = function fail() {
5944
+ return reject(new ResultMonitorTransportError());
5945
+ };
5946
+ request.onerror = fail;
5947
+ request.onabort = fail;
5948
+ request.ontimeout = fail;
5546
5949
  request.send();
5547
5950
  });
5548
5951
  }
5952
+ /**
5953
+ * Polls the GPayments result monitor (`secondary_url`) until `AuthResultReady`. It is the primary source of
5954
+ * `chargeAuthChallengeCompleted` (the monitor flips as soon as the issuer's RReq reaches the 3DS Server) and
5955
+ * the fallback transport for the outcome itself (`GET /handle`) when the callback message never arrives —
5956
+ * the only transport for decoupled challenges. Stops once an outcome was obtained or the lifecycle closed.
5957
+ * Transport failures are retried on the same cadence; an unparsable body or an unknown event is fatal.
5958
+ */
5549
5959
  }, {
5550
5960
  key: "doPolling",
5551
- value: function doPolling(url, charge3dsId) {
5552
- var _this3 = this;
5961
+ value: function doPolling(url, charge3dsId, intervalMs) {
5962
+ var _this7 = this;
5963
+ this.stopResultPolling();
5964
+ if (this.resultRead || this.challengeLifecycleClosed) {
5965
+ return;
5966
+ }
5967
+ var schedule = function schedule() {
5968
+ _this7.resultPollTimer = setTimeout(function () {
5969
+ _this7.resultPollTimer = null;
5970
+ _this7.doPolling(url, charge3dsId, intervalMs);
5971
+ }, intervalMs);
5972
+ };
5553
5973
  this.externalAPI('GET', url).then(function (data) {
5974
+ if (_this7.resultRead || _this7.challengeLifecycleClosed) {
5975
+ return;
5976
+ }
5554
5977
  if (!data.event || data.event === 'AuthResultNotReady') {
5555
- setTimeout(function () {
5556
- _this3.doPolling(url, charge3dsId);
5557
- }, 2000);
5978
+ schedule();
5558
5979
  } else if (data.event === 'AuthResultReady') {
5559
- _this3.processResult(charge3dsId);
5980
+ _this7.emitChallengeCompleted(charge3dsId, 'poll');
5981
+ _this7.processResult(charge3dsId);
5560
5982
  } else {
5561
5983
  throw new Error('Event not supported');
5562
5984
  }
5563
5985
  })["catch"](function (err) {
5564
- return _this3.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this3.parseError(err, charge3dsId));
5986
+ if (err instanceof ResultMonitorTransportError) {
5987
+ if (!_this7.resultRead && !_this7.challengeLifecycleClosed) {
5988
+ schedule();
5989
+ }
5990
+ return;
5991
+ }
5992
+ _this7.finishChallengeLifecycle();
5993
+ _this7.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this7.parseError(err, charge3dsId));
5565
5994
  });
5566
5995
  }
5996
+ /**
5997
+ * Branches on the authentication outcome — delivered by the API through the callback message
5998
+ * (`process_status` → `status`) or, in two-step mode, returned by `/process` (same shape).
5999
+ */
5567
6000
  }, {
5568
- key: "performAuthentication",
5569
- value: function performAuthentication(_ref4) {
5570
- var _this4 = this;
5571
- var charge_3ds_id = _ref4.charge_3ds_id;
5572
- var _a;
5573
- this.iFrameAuthorization.remove();
5574
- (_a = this.iFrameSecondaryUrl) === null || _a === void 0 ? void 0 : _a.remove();
5575
- this.api.charge().standalone3dsProcess({
5576
- charge_3ds_id: charge_3ds_id
5577
- }).then(function (authenticationResult) {
5578
- var _a, _b;
5579
- if (authenticationResult.status === AUTHENTICATION_STATUS.SUCCESS) {
5580
- _this4.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_SUCCESS, _this4.parseHandleResponse(authenticationResult, charge_3ds_id));
5581
- } else if (authenticationResult.status === AUTHENTICATION_STATUS.PENDING) {
5582
- if ((_a = authenticationResult === null || authenticationResult === void 0 ? void 0 : authenticationResult.result) === null || _a === void 0 ? void 0 : _a.challenge) {
5583
- _this4.eventEmitter.emit(GPAYMENTS_EVENT.CHALLENGE, _this4.parseHandleResponse(authenticationResult, charge_3ds_id));
5584
- _this4.initializeIFrames(authenticationResult.result.challenge_url, undefined, 'Authentication Challenge', false);
5585
- if (authenticationResult.result.secondary_url) {
5586
- _this4.doPolling(authenticationResult.result.secondary_url, charge_3ds_id);
5587
- }
5588
- } else if ((_b = authenticationResult === null || authenticationResult === void 0 ? void 0 : authenticationResult.result) === null || _b === void 0 ? void 0 : _b.decoupled_challenge) {
5589
- _this4.eventEmitter.emit(GPAYMENTS_EVENT.DECOUPLED, _this4.parseHandleResponse(authenticationResult, charge_3ds_id));
5590
- if (authenticationResult.result.secondary_url) {
5591
- _this4.doPolling(authenticationResult.result.secondary_url, charge_3ds_id);
5592
- }
6001
+ key: "handleAuthenticationOutcome",
6002
+ value: function handleAuthenticationOutcome(authenticationResult, charge_3ds_id) {
6003
+ var _a, _b, _c;
6004
+ if (authenticationResult.status !== AUTHENTICATION_STATUS.PENDING) {
6005
+ // terminal outcome — a later `chargeAuthSuccess` message or poll must not emit a second result
6006
+ this.resultRead = true;
6007
+ }
6008
+ if (authenticationResult.status === AUTHENTICATION_STATUS.SUCCESS) {
6009
+ this.finishChallengeLifecycle();
6010
+ this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_SUCCESS, this.parseHandleResponse(authenticationResult, charge_3ds_id));
6011
+ } else if (authenticationResult.status === AUTHENTICATION_STATUS.PENDING) {
6012
+ if ((_a = authenticationResult === null || authenticationResult === void 0 ? void 0 : authenticationResult.result) === null || _a === void 0 ? void 0 : _a.challenge) {
6013
+ this.eventEmitter.emit(GPAYMENTS_EVENT.CHALLENGE, this.parseHandleResponse(authenticationResult, charge_3ds_id));
6014
+ var onChallengeLoad = this.startChallengeLifecycle(charge_3ds_id);
6015
+ this.initializeIFrames(authenticationResult.result.challenge_url, undefined, 'Authentication Challenge', false, onChallengeLoad);
6016
+ this.armChallengeLoadedFallback(charge_3ds_id);
6017
+ if (authenticationResult.result.secondary_url) {
6018
+ this.doPolling(authenticationResult.result.secondary_url, charge_3ds_id, CHALLENGE_RESULT_POLL_INTERVAL_MS);
6019
+ }
6020
+ } else if ((_b = authenticationResult === null || authenticationResult === void 0 ? void 0 : authenticationResult.result) === null || _b === void 0 ? void 0 : _b.decoupled_challenge) {
6021
+ this.challengeCompletedEmitted = false;
6022
+ this.challengeLifecycleClosed = false;
6023
+ this.eventEmitter.emit(GPAYMENTS_EVENT.DECOUPLED, this.parseHandleResponse(authenticationResult, charge_3ds_id));
6024
+ if (authenticationResult.result.secondary_url) {
6025
+ this.doPolling(authenticationResult.result.secondary_url, charge_3ds_id, DECOUPLED_RESULT_POLL_INTERVAL_MS);
5593
6026
  }
5594
6027
  } else {
5595
- return _this4.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, _this4.parseHandleResponse(authenticationResult, charge_3ds_id));
5596
- }
5597
- }, function (err) {
5598
- _this4.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, _this4.parseError(err, charge_3ds_id));
5599
- });
6028
+ // pending but nothing to run (no challenge delivered) — fail rather than hang silently
6029
+ // with the iframes already removed and no further message ever coming
6030
+ this.resultRead = true;
6031
+ this.finishChallengeLifecycle();
6032
+ this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, this.parseHandleResponse(authenticationResult, charge_3ds_id));
6033
+ }
6034
+ } else if (authenticationResult.status === AUTHENTICATION_STATUS.ERROR) {
6035
+ // the API rejected the authentication, or could not run it inside the callback
6036
+ this.finishChallengeLifecycle();
6037
+ this.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, this.parseError((_c = authenticationResult.error) !== null && _c !== void 0 ? _c : authenticationResult, charge_3ds_id));
6038
+ } else {
6039
+ this.finishChallengeLifecycle();
6040
+ this.eventEmitter.emit(GPAYMENTS_EVENT.AUTH_ERROR, this.parseHandleResponse(authenticationResult, charge_3ds_id));
6041
+ }
5600
6042
  }
5601
6043
  }]);
5602
6044
  }();
@@ -5623,16 +6065,61 @@ var Standalone3dsService = /*#__PURE__*/function () {
5623
6065
  api.setEnv(this.env, this.alias);
5624
6066
  switch (tokenData.service_type) {
5625
6067
  case STANDALONE_3DS_GATEWAYS.GPAYMENTS:
5626
- new GPaymentsService(this.container, api, this.eventEmitter).load(tokenData, options.title);
6068
+ this.gpaymentsService = new GPaymentsService(this.container, api, this.eventEmitter, this.getTrustedMessageOrigins(api));
6069
+ this.gpaymentsService.load(tokenData, options.title);
5627
6070
  break;
5628
6071
  }
5629
6072
  }
6073
+ /**
6074
+ * Two-step mode: forwards `Canvas3ds.authenticate()` to the provider flow. Calling it before `load()` is an
6075
+ * integration bug (nothing to authenticate yet): it emits `error` and is not remembered.
6076
+ */
6077
+ }, {
6078
+ key: "authenticate",
6079
+ value: function authenticate(token) {
6080
+ if (!this.gpaymentsService) {
6081
+ this.eventEmitter.emit(GPAYMENTS_EVENT.ERROR, {
6082
+ charge_3ds_id: Standalone3dsService.readCharge3dsId(token),
6083
+ error: {
6084
+ message: 'Canvas3ds.authenticate() called before load()'
6085
+ }
6086
+ });
6087
+ return;
6088
+ }
6089
+ this.gpaymentsService.authenticate();
6090
+ }
6091
+ /** `charge_3ds_id` from the standalone 3DS charge token, `undefined` when it cannot be decoded. */
6092
+ }, {
6093
+ key: "getTrustedMessageOrigins",
6094
+ value:
6095
+ /**
6096
+ * Origins allowed to deliver a processed 3DS outcome to the page via postMessage: the Paydock API
6097
+ * (inline callback page) and the Paydock widget (remote-app landing page), for the current env/alias.
6098
+ */
6099
+ function getTrustedMessageOrigins(api) {
6100
+ var origins = [api.getApiOrigin()];
6101
+ try {
6102
+ var widgetEnv = new Env(WIDGET_URL, this.env);
6103
+ widgetEnv.setEnv(this.env, this.alias);
6104
+ origins.push(ApiBase.toOrigin(widgetEnv.getConf().url));
6105
+ } catch (_a) {
6106
+ // widget origin unknown for this env — the API origin is enough
6107
+ }
6108
+ return origins;
6109
+ }
5630
6110
  }, {
5631
6111
  key: "setEnv",
5632
6112
  value: function setEnv(env, alias) {
5633
6113
  this.env = env;
5634
6114
  this.alias = alias;
5635
6115
  }
6116
+ }], [{
6117
+ key: "readCharge3dsId",
6118
+ value: function readCharge3dsId(token) {
6119
+ var _a;
6120
+ var parsedToken = AccessToken.validateJWT(token);
6121
+ return parsedToken ? (_a = AccessToken.extractData(parsedToken.body)) === null || _a === void 0 ? void 0 : _a.charge_3ds_id : undefined;
6122
+ }
5636
6123
  }]);
5637
6124
  }();
5638
6125
 
@@ -5795,11 +6282,14 @@ var TOKEN_FORMAT$2;
5795
6282
  * @const STANDALONE_3DS_EVENT
5796
6283
  *
5797
6284
  * @type {object}
5798
- * @param {string} CHARGE_AUTH_SUCCESS=chargeAuthSuccess
5799
- * @param {string} CHARGE_AUTH_REJECT=chargeAuthReject
5800
- * @param {string} CHARGE_AUTH_DECOUPLED=chargeAuthDecoupled
5801
- * @param {string} CHARGE_AUTH_CHALLENGE=chargeAuthChallenge
5802
- * @param {string} CHARGE_AUTH_INFO=chargeAuthInfo
6285
+ * @param {string} AUTH_SUCCESS=chargeAuthSuccess
6286
+ * @param {string} AUTH_ERROR=chargeAuthReject
6287
+ * @param {string} DECOUPLED=chargeAuthDecoupled
6288
+ * @param {string} CHALLENGE=chargeAuthChallenge
6289
+ * @param {string} READY=chargeAuthReady - two-step mode only: fingerprint done, waiting for `authenticate()`
6290
+ * @param {string} CHALLENGE_LOADED=chargeAuthChallengeLoaded - challenge iframe painted (first `load`, or 2.5 s fallback); reveal your challenge UI here
6291
+ * @param {string} CHALLENGE_COMPLETED=chargeAuthChallengeCompleted - the shopper finished the challenge (issuer result delivered to the 3DS Server); cover the challenge iframe with your own loader until the terminal event
6292
+ * @param {string} INFO=chargeAuthInfo
5803
6293
  * @param {string} ERROR=error
5804
6294
  */
5805
6295
  /**
@@ -5926,6 +6416,39 @@ var Canvas3ds = /*#__PURE__*/function () {
5926
6416
  });
5927
6417
  }
5928
6418
  }
6419
+ /**
6420
+ * Two-step mode only (`_3ds.authentication_flow: 'two_step'`): runs the authentication the API deferred after the
6421
+ * fingerprint. Call it when the shopper confirms (e.g. presses "Pay"); the outcome arrives through the
6422
+ * usual events (`chargeAuthChallenge`, `chargeAuthSuccess`, `chargeAuthReject`, `error`).
6423
+ *
6424
+ * Never throws. After `chargeAuthReady` the authentication starts at once; before it, the call is
6425
+ * remembered and runs as soon as the fingerprint completes. One-step charges, repeated calls and calls after
6426
+ * a terminal outcome are no-ops. For inbuilt 3DS (`html` / `url`) tokens it is a silent no-op: no event is
6427
+ * emitted at all, so do not wait for `error` there. Calling it before `load()` is an integration error: it emits `error` and
6428
+ * is not remembered. If `/process` could not be reached (`error` with `error_code` `service_unreachable` /
6429
+ * `aborted`), `authenticate()` may be called once more; any other `error`, and any failure of that retry,
6430
+ * is final.
6431
+ * No client-side deadline: a stale 3DS Server session surfaces as `error` / `chargeAuthReject`.
6432
+ *
6433
+ * @example
6434
+ * const widget = new Canvas3ds('#widget', token); // charge created with _3ds.authentication_flow: 'two_step'
6435
+ * widget.on('chargeAuthReady', () => payButton.disabled = false);
6436
+ * widget.on('chargeAuthChallenge', () => showChallengeModal());
6437
+ * widget.on('chargeAuthSuccess', (data) => completePayment(data.charge_3ds_id));
6438
+ * widget.on('chargeAuthReject', () => showDeclined());
6439
+ * widget.on('error', () => showError());
6440
+ * widget.load(); // fingerprint runs while the shopper reviews the order
6441
+ *
6442
+ * payButton.addEventListener('click', () => widget.authenticate());
6443
+ */
6444
+ }, {
6445
+ key: "authenticate",
6446
+ value: function authenticate() {
6447
+ if (this.token.format !== TOKEN_FORMAT$2.STANDALONE_3DS) {
6448
+ return;
6449
+ }
6450
+ this.standalone3dsService.authenticate(this.token.content);
6451
+ }
5929
6452
  /**
5930
6453
  * Using this method you can hide widget after load
5931
6454
  * @param {boolean} [saveSize=false] - using this param you can save iframe's size
@@ -6181,6 +6704,24 @@ var SUPPORTED_CARD_TYPES = {
6181
6704
  EFTPOS_WHITE: 'eftpos_white',
6182
6705
  UNIONPAY: 'unionpay'
6183
6706
  };
6707
+ /**
6708
+ * Card schemes the widget is able to resolve from a card number, and therefore the only values
6709
+ * `setAllowedCardSchemes` accepts. This is a separate vocabulary from SUPPORTED_CARD_TYPES, which drives the
6710
+ * card icons: it omits the icon-only variants `visa_white` / `eftpos_white`, and the `laser` / `maestro`
6711
+ * identifiers the widget can never resolve — allowing those would be configuration that can never match.
6712
+ */
6713
+ var CARD_SCHEME = {
6714
+ AMEX: 'amex',
6715
+ AUSBC: 'ausbc',
6716
+ DINERS: 'diners',
6717
+ DISCOVER: 'discover',
6718
+ EFTPOS: 'eftpos',
6719
+ JAPCB: 'japcb',
6720
+ MASTERCARD: 'mastercard',
6721
+ SOLO: 'solo',
6722
+ UNIONPAY: 'unionpay',
6723
+ VISA: 'visa'
6724
+ };
6184
6725
  var SUPPORTED_CHECKOUT_META_COLLECTION = [].concat([
6185
6726
  // Paypal
6186
6727
  'brand_name', 'cart_border_color', 'reference', 'email', 'hdr_img', 'logo_img', 'pay_flow_color', 'first_name', 'last_name', 'address_line', 'address_line2', 'address_city', 'address_state', 'address_postcode', 'address_country', 'phone', 'hide_shipping_address'], [
@@ -8365,7 +8906,7 @@ var AfterPayWalletService = /*#__PURE__*/function (_WalletService) {
8365
8906
  }]);
8366
8907
  }(WalletService);
8367
8908
 
8368
- /*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */
8909
+ /*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
8369
8910
 
8370
8911
  var purify_cjs;
8371
8912
  var hasRequiredPurify_cjs;
@@ -8685,7 +9226,7 @@ function requirePurify_cjs () {
8685
9226
  const text = freeze(['#text']);
8686
9227
 
8687
9228
  const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
8688
- const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
9229
+ const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dominant-baseline', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-orientation', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
8689
9230
  const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
8690
9231
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
8691
9232
 
@@ -8798,7 +9339,7 @@ function requirePurify_cjs () {
8798
9339
  function createDOMPurify() {
8799
9340
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
8800
9341
  const DOMPurify = root => createDOMPurify(root);
8801
- DOMPurify.version = '3.4.11';
9342
+ DOMPurify.version = '3.4.13';
8802
9343
  DOMPurify.removed = [];
8803
9344
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
8804
9345
  // Not running in a browser, provide a factory function
@@ -8829,6 +9370,7 @@ function requirePurify_cjs () {
8829
9370
  const getAttributes = lookupGetter(ElementPrototype, 'attributes');
8830
9371
  const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
8831
9372
  const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
9373
+ const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, 'ownerDocument') : null;
8832
9374
  // As per issue #47, the web-components registry is inherited by a
8833
9375
  // new document created via createHTMLDocument. As per the spec
8834
9376
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
@@ -9480,6 +10022,13 @@ function requirePurify_cjs () {
9480
10022
  * @param root the in-place root to empty
9481
10023
  */
9482
10024
  const _neutralizeRoot = function _neutralizeRoot(root) {
10025
+ /* Strip every disallowed attribute (on* handlers included) off the whole
10026
+ subtree BEFORE detaching anything. Detaching first would hand back
10027
+ handler-bearing originals (e.g. an already-loading `<img onerror>`)
10028
+ whose queued resource event still fires in page scope after we throw.
10029
+ Clobber-safe reads; a doomed clobbered node's own attributes are
10030
+ irrelevant while its non-clobbered descendants are reached and scrubbed. */
10031
+ _neutralizeSubtree(root);
9483
10032
  const childNodes = getChildNodes(root);
9484
10033
  if (childNodes) {
9485
10034
  const snapshot = [];
@@ -9607,6 +10156,82 @@ function requirePurify_cjs () {
9607
10156
  }
9608
10157
  }
9609
10158
  };
10159
+ /**
10160
+ * _neutralizePatchLinkage
10161
+ *
10162
+ * IN_PLACE entry pre-pass (declarative-partial-updates / streaming
10163
+ * hardening, https://github.com/WICG/declarative-partial-updates).
10164
+ *
10165
+ * The main walk strips patch linkage (`for`/`patchsrc`) and removes range
10166
+ * markers (PIs / markup comments) node-by-node, in document order, AS it
10167
+ * reaches each node. On a live in-place root that leaves a window: from the
10168
+ * moment the root is connected until the walk arrives at a given node, that
10169
+ * node's linkage is live. A patch applied on connection/stream can fire as
10170
+ * a microtask during the walk and inject or teleport an unsanitized DOM
10171
+ * range into a region the iterator has already passed and will not revisit,
10172
+ * so the post-return "tree is sanitized" contract is violated. Sweep the
10173
+ * whole tree once up front and sever every linkage before the walk begins,
10174
+ * closing that window.
10175
+ *
10176
+ * This CANNOT undo a patch that already fired before sanitize ran — that is
10177
+ * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat —
10178
+ * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML
10179
+ * to group with the rest of the declarative-partial-updates handling and
10180
+ * stay overridable, consistent with the codebase.
10181
+ *
10182
+ * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a
10183
+ * clobbered root cannot defeat the sweep of its non-clobbered descendants.
10184
+ *
10185
+ * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe
10186
+ * .html Q1): this mirrors the existing policy of keeping `for` on
10187
+ * <label>/<output>. If the shipping feature can drive a patch through a
10188
+ * surviving `for`-on-label/output + `id` pair, this pre-pass and the
10189
+ * attribute check at _isBasicCustomElement's caller must additionally drop
10190
+ * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified.
10191
+ *
10192
+ * @param root the in-place root to sweep
10193
+ */
10194
+ const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
10195
+ if (!SAFE_FOR_XML) {
10196
+ return;
10197
+ }
10198
+ const stack = [root];
10199
+ while (stack.length > 0) {
10200
+ const node = stack.pop();
10201
+ const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
10202
+ /* Remove range markers (the target side of a patch linkage): every
10203
+ processing instruction, and any markup-bearing comment. */
10204
+ if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
10205
+ try {
10206
+ remove(node);
10207
+ } catch (_) {
10208
+ /* Best-effort */
10209
+ }
10210
+ continue;
10211
+ }
10212
+ /* Strip patch-source attributes (the source side) off elements. */
10213
+ if (nodeType === NODE_TYPE.element) {
10214
+ const element = node;
10215
+ const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName);
10216
+ try {
10217
+ if (element.hasAttribute && element.hasAttribute('patchsrc')) {
10218
+ element.removeAttribute('patchsrc');
10219
+ }
10220
+ if (element.hasAttribute && element.hasAttribute('for') && lcTag !== 'label' && lcTag !== 'output') {
10221
+ element.removeAttribute('for');
10222
+ }
10223
+ } catch (_) {
10224
+ /* Clobbered removeAttribute/hasAttribute on a doomed node — ignore */
10225
+ }
10226
+ }
10227
+ const childNodes = getChildNodes(node);
10228
+ if (childNodes) {
10229
+ for (let i = childNodes.length - 1; i >= 0; --i) {
10230
+ stack.push(childNodes[i]);
10231
+ }
10232
+ }
10233
+ }
10234
+ };
9610
10235
  /**
9611
10236
  * _initDocument
9612
10237
  *
@@ -9664,7 +10289,17 @@ function requirePurify_cjs () {
9664
10289
  * @return The created NodeIterator
9665
10290
  */
9666
10291
  const _createNodeIterator = function _createNodeIterator(root) {
9667
- return createNodeIterator.call(root.ownerDocument || root, root,
10292
+ /* Read ownerDocument through the cached Node.prototype getter, never the
10293
+ direct property. HTMLFormElement has [LegacyOverrideBuiltIns], so a
10294
+ clobbering child (<input name="ownerDocument"> or a form-associated
10295
+ external input) shadows the prototype getter and makes a direct read
10296
+ return that <input>. createNodeIterator.call(<input>, ...) then throws
10297
+ "Illegal invocation", and on the IN_PLACE path that throw lands before
10298
+ the walk's fail-closed barrier - leaving the caller's live tree, with
10299
+ any already-armed handler in it, un-neutralized. The cached getter
10300
+ returns the real Document regardless of the clobber. */
10301
+ const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
10302
+ return createNodeIterator.call(doc || root, root,
9668
10303
  // eslint-disable-next-line no-bitwise
9669
10304
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
9670
10305
  };
@@ -9704,7 +10339,11 @@ function requirePurify_cjs () {
9704
10339
  const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
9705
10340
  var _node$querySelectorAl;
9706
10341
  node.normalize();
9707
- const walker = createNodeIterator.call(node.ownerDocument || node, node,
10342
+ /* Clobber-safe ownerDocument read, same reasoning as _createNodeIterator:
10343
+ under SAFE_FOR_TEMPLATES this runs on the live IN_PLACE root, which may
10344
+ carry a form-named-getter override of ownerDocument. */
10345
+ const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
10346
+ const walker = createNodeIterator.call(doc || node, node,
9708
10347
  // eslint-disable-next-line no-bitwise
9709
10348
  NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
9710
10349
  let currentNode = walker.nextNode();
@@ -9857,15 +10496,21 @@ function requirePurify_cjs () {
9857
10496
  /**
9858
10497
  * Handle a node whose tag is forbidden or not allowlisted: keep
9859
10498
  * allowed custom elements (false return exits _sanitizeElements
9860
- * early - namespace/fallback checks and the afterSanitizeElements
9861
- * hook are intentionally skipped for kept custom elements), else
9862
- * hoist content per KEEP_CONTENT and remove.
10499
+ * early - the namespace and fallback-tag removal checks are
10500
+ * intentionally skipped for kept custom elements), else hoist
10501
+ * content per KEEP_CONTENT and remove.
10502
+ *
10503
+ * A kept custom element is the ONLY case in which this function
10504
+ * returns false, so the caller uses that return value to run the
10505
+ * afterSanitizeElements hook on the kept element and keep the
10506
+ * element-hook lifecycle consistent with normal allowlisted
10507
+ * elements (GHSA-c2j3-45gr-mqc4).
9863
10508
  *
9864
10509
  * @param currentNode the disallowed node
9865
10510
  * @param tagName the node's transformCaseFunc'd tag name
9866
10511
  * @return true if the node was removed, false if kept
9867
10512
  */
9868
- const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) {
10513
+ const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
9869
10514
  /* Check if we have a custom element to handle */
9870
10515
  if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
9871
10516
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
@@ -9888,27 +10533,26 @@ function requirePurify_cjs () {
9888
10533
  const childNodes = getChildNodes(currentNode);
9889
10534
  if (childNodes && parentNode) {
9890
10535
  const childCount = childNodes.length;
9891
- /* In-place: hoist the *original* children so the iterator visits
9892
- and sanitises them through the same allowlist pass as every other
9893
- node. The caller built the tree in the live document, so the
9894
- originals carry already-queued resource events (`<img onerror>`,
9895
- `<video>`/`<audio>` error, lazy/`onload`, …); cloning would leave
9896
- those originals detached but still armed, firing in page scope
9897
- while the returned tree looked clean. Moving is safe in-place: the
9898
- root is pre-validated as an allowed tag and so is never the node
9899
- being removed, which keeps `parentNode` inside the iterator root
9900
- and the relocated child inside the serialised tree.
9901
- Otherwise (string / DOM-copy paths): clone. The iterator is rooted
9902
- at — and the result serialised from — `body`, so a restrictive
9903
- ALLOWED_TAGS that removes `body` itself must leave its content in
9904
- place, which only cloning does; and those paths parse into an
9905
- inert document, so their discarded originals never had a queued
9906
- event to neutralise.
10536
+ /* Hoist by moving each child up one level rather than deep-cloning
10537
+ it. Moving transfers every descendant exactly once, so a chain of
10538
+ nested disallowed elements costs O(n) instead of the O(n^2) that
10539
+ re-cloning the shrinking subtree at each level produced; it also
10540
+ empties the removed original, so `DOMPurify.removed` no longer
10541
+ pins whole subtrees. Moving preserves the in-place guarantee too:
10542
+ an original carrying already-queued resource events (`<img
10543
+ onerror>`, `<video>`/`<audio>` error, lazy/`onload`, …) is
10544
+ relocated and sanitised rather than left detached but still armed.
10545
+ The sole case that must clone is removing the walk root itself.
10546
+ The result is serialised from the root's subtree, so a restrictive
10547
+ ALLOWED_TAGS that strips the root (`body` on the string path) must
10548
+ leave the content inside it, which only cloning does. In IN_PLACE
10549
+ the root is pre-validated as an allowed tag and so is never removed
10550
+ here, so that path always takes the move branch.
9907
10551
  `childNodes` is live; a tail-to-head walk keeps `childNodes[i]`
9908
10552
  valid whether we move (drops the trailing entry) or clone (leaves
9909
10553
  the list intact). */
9910
10554
  for (let i = childCount - 1; i >= 0; --i) {
9911
- const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true);
10555
+ const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i];
9912
10556
  parentNode.insertBefore(hoisted, getNextSibling(currentNode));
9913
10557
  }
9914
10558
  }
@@ -9916,6 +10560,26 @@ function requirePurify_cjs () {
9916
10560
  _forceRemove(currentNode);
9917
10561
  return true;
9918
10562
  };
10563
+ /**
10564
+ * Fork a hook-mutable allowlist off its shared binding the first time a
10565
+ * (possibly lazily-installed) uponSanitize* hook is about to see it, so the
10566
+ * hook cannot widen the per-instance default or the setConfig binding by
10567
+ * reference and leak past the call. Returns the set unchanged once it is
10568
+ * already call-local, so repeated calls across elements are idempotent.
10569
+ *
10570
+ * @param hookList the uponSanitize* hook array for this event
10571
+ * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding
10572
+ * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant
10573
+ * @param setConfigSet the captured setConfig() binding, or null
10574
+ * @return a call-local clone if a hook is present and set is still shared,
10575
+ * else set unchanged
10576
+ */
10577
+ const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) {
10578
+ if (hookList.length === 0) {
10579
+ return set;
10580
+ }
10581
+ return set === defaultSet || set === setConfigSet ? clone(set) : set;
10582
+ };
9919
10583
  /**
9920
10584
  * _sanitizeElements
9921
10585
  *
@@ -9925,9 +10589,20 @@ function requirePurify_cjs () {
9925
10589
  * @param currentNode to check for permission to exist
9926
10590
  * @return true if node was killed, false if left alive
9927
10591
  */
9928
- const _sanitizeElements = function _sanitizeElements(currentNode) {
10592
+ // eslint-disable-next-line complexity
10593
+ const _sanitizeElements = function _sanitizeElements(currentNode, root) {
9929
10594
  /* Execute a hook if present */
9930
10595
  _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
10596
+ /* A hook may have detached the node - treat it as removed (see the
10597
+ detached-node comment after the uponSanitizeElement hook below). On
10598
+ the IN_PLACE path, neutralize the detached subtree first so a queued
10599
+ resource handler on it cannot fire in page scope after we return. */
10600
+ if (currentNode !== root && getParentNode(currentNode) === null) {
10601
+ if (IN_PLACE) {
10602
+ _neutralizeSubtree(currentNode);
10603
+ }
10604
+ return true;
10605
+ }
9931
10606
  /* Check if element is clobbered or can clobber */
9932
10607
  if (_isClobbered(currentNode)) {
9933
10608
  _forceRemove(currentNode);
@@ -9935,11 +10610,47 @@ function requirePurify_cjs () {
9935
10610
  }
9936
10611
  /* Now let's check the element's type and name */
9937
10612
  const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
10613
+ /* Close the pre-walk clone-guard's timing gap: an uponSanitizeElement
10614
+ hook may have been installed after that guard sampled the hook arrays
10615
+ (e.g. lazily from beforeSanitizeElements), leaving ALLOWED_TAGS still
10616
+ aliasing a shared binding that a widening hook would mutate by
10617
+ reference. Fork it before exposing it to the hook. */
10618
+ ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
9938
10619
  /* Execute a hook if present */
9939
10620
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
9940
10621
  tagName,
9941
10622
  allowedTags: ALLOWED_TAGS
9942
10623
  });
10624
+ /* A hook may have detached the node from the tree — a long-standing
10625
+ user pattern (issue #469; draw.io-style foreignObject filtering).
10626
+ Per the cached, unclobberable parentNode getter the node is
10627
+ genuinely out of the tree, so it can reach neither the serialized
10628
+ output nor an IN_PLACE live tree; treat it as removed and stop
10629
+ processing it. Without this guard, the unsafe-node / namespace
10630
+ checks below would call _forceRemove on a parentless node and hit
10631
+ the REPORT-3 fail-closed throw — which exists for nodes DOMPurify
10632
+ wants gone but *cannot* detach (clobbered / parentless roots), the
10633
+ opposite of a node that is already safely gone. The walk root is
10634
+ exempt: a detached IN_PLACE root is legitimate input and must still
10635
+ be fully sanitized, and a kill-decision on it must keep hitting the
10636
+ REPORT-3 throw. Nodes detached by hooks stay the hook's
10637
+ responsibility for placement: they are not recorded in
10638
+ DOMPurify.removed, so the post-walk IN_PLACE pass (which iterates
10639
+ DOMPurify.removed) does not reach them. But a hook-detached subtree
10640
+ can still hold a queued resource-event handler - e.g. an <img onload>
10641
+ that began loading when the caller built the live tree - which fires
10642
+ in page scope after sanitize returns even though the handler never
10643
+ reached the returned tree. That is the audit-5 F1 hazard, and the
10644
+ documented node.remove() hook pattern walks straight into it. So on
10645
+ the IN_PLACE path we neutralize the detached subtree inline here,
10646
+ stripping its non-allow-listed attributes before returning, exactly
10647
+ as the post-walk pass does for _forceRemove'd subtrees. */
10648
+ if (currentNode !== root && getParentNode(currentNode) === null) {
10649
+ if (IN_PLACE) {
10650
+ _neutralizeSubtree(currentNode);
10651
+ }
10652
+ return true;
10653
+ }
9943
10654
  /* Remove mXSS vectors, processing instructions and risky comments */
9944
10655
  if (_isUnsafeNode(currentNode, tagName)) {
9945
10656
  _forceRemove(currentNode);
@@ -9947,7 +10658,22 @@ function requirePurify_cjs () {
9947
10658
  }
9948
10659
  /* Remove element if anything forbids its presence */
9949
10660
  if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
9950
- return _sanitizeDisallowedNode(currentNode, tagName);
10661
+ const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
10662
+ /* A false return means the node is a custom element kept via
10663
+ CUSTOM_ELEMENT_HANDLING - the only keep path through
10664
+ _sanitizeDisallowedNode. Run afterSanitizeElements on it so the
10665
+ element-hook lifecycle matches normal allowlisted elements: a
10666
+ security policy applied in this hook (e.g. stripping an attribute
10667
+ from every surviving element) must not silently skip kept custom
10668
+ elements (GHSA-c2j3-45gr-mqc4). This mirrors the normal-element
10669
+ tail below - the hook runs, then the walker's subsequent
10670
+ _sanitizeAttributes pass sanitizes the element's attributes. The
10671
+ deliberately skipped namespace and fallback-tag removal checks stay
10672
+ skipped; they are removal decisions, not the hook contract. */
10673
+ if (removed === false) {
10674
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
10675
+ }
10676
+ return removed;
9951
10677
  }
9952
10678
  /* Check whether element has a valid namespace.
9953
10679
  Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
@@ -9994,6 +10720,33 @@ function requirePurify_cjs () {
9994
10720
  if (FORBID_ATTR[lcName]) {
9995
10721
  return false;
9996
10722
  }
10723
+ /* Reject declarative-partial-updates patch-linkage attributes
10724
+ (https://github.com/WICG/declarative-partial-updates).
10725
+ Empirical note (Chrome 150, verified — see
10726
+ test/declarative-patch-probe-v3.html): expansion is NOT applied after
10727
+ sanitization. For the string path it fires during sanitize()'s own
10728
+ parse, so the walk sees and sanitizes the fully materialized expanded
10729
+ tree — teleports into MathML/SVG integration points included; a
10730
+ weaponized `<template for>`->`<img onerror>` comes back with the handler
10731
+ stripped. For the IN_PLACE path it fires on connection, before the walk.
10732
+ Either way DOMPurify is NOT blind to the patch.
10733
+ This removal is therefore defense-in-depth rather than the sole barrier:
10734
+ it prevents live linkage from surviving into the OUTPUT and re-expanding
10735
+ in the caller's context, and keeps behaviour deterministic if a future
10736
+ engine defers expansion. `for` is legitimate only on <label>/<output>;
10737
+ anywhere else (notably <template for>) it links the element to a patch
10738
+ target and teleports or removes an arbitrary DOM range by id/marker name.
10739
+ `patchsrc` fetches remote markup and is treated as a script-loading
10740
+ mechanism (CSP). Gated on SAFE_FOR_XML so the removal groups with the
10741
+ other structural-threat checks and stays overridable, consistent with
10742
+ the rest of the codebase. PI range markers are already removed by
10743
+ _isUnsafeNode. */
10744
+ if (SAFE_FOR_XML && lcName === 'patchsrc') {
10745
+ return false;
10746
+ }
10747
+ if (SAFE_FOR_XML && lcName === 'for' && lcTag !== 'label' && lcTag !== 'output') {
10748
+ return false;
10749
+ }
9997
10750
  /* Make sure attribute cannot clobber */
9998
10751
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
9999
10752
  return false;
@@ -10110,6 +10863,9 @@ function requirePurify_cjs () {
10110
10863
  if (!attributes || _isClobbered(currentNode)) {
10111
10864
  return;
10112
10865
  }
10866
+ /* Same lazy-install guard as uponSanitizeElement (see there): fork the
10867
+ attribute allowlist off its shared binding before a hook can see it. */
10868
+ ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
10113
10869
  const hookEvent = {
10114
10870
  attrName: '',
10115
10871
  attrValue: '',
@@ -10203,7 +10959,7 @@ function requirePurify_cjs () {
10203
10959
  /* Execute a hook if present */
10204
10960
  _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
10205
10961
  /* Sanitize tags and elements */
10206
- _sanitizeElements(shadowNode);
10962
+ _sanitizeElements(shadowNode, fragment);
10207
10963
  /* Check attributes next */
10208
10964
  _sanitizeAttributes(shadowNode);
10209
10965
  /* Deep shadow DOM detected.
@@ -10394,6 +11150,11 @@ function requirePurify_cjs () {
10394
11150
  keep using and whose return value they ignore — unsanitized. REPORT-2. */
10395
11151
  const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty);
10396
11152
  if (inPlace) {
11153
+ /* Declarative-partial-updates / streaming pre-pass: sever every patch
11154
+ linkage across the live tree BEFORE the walk, so no patch can fire
11155
+ mid-walk and inject into an already-processed region. Runs first, so
11156
+ it also covers the forbidden/clobbered roots that throw below. */
11157
+ _neutralizePatchLinkage(dirty);
10397
11158
  /* Do some early pre-sanitization to avoid unsafe root nodes.
10398
11159
  Read nodeName through the cached prototype getter — a clobbering
10399
11160
  child named "nodeName" on the form root would otherwise shadow
@@ -10403,6 +11164,9 @@ function requirePurify_cjs () {
10403
11164
  if (typeof nn === 'string') {
10404
11165
  const tagName = transformCaseFunc(nn);
10405
11166
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
11167
+ /* Fail closed on a live root: neutralize handlers/children before
11168
+ throwing, exactly as the mid-walk abort path does. */
11169
+ _neutralizeRoot(dirty);
10406
11170
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
10407
11171
  }
10408
11172
  }
@@ -10417,6 +11181,10 @@ function requirePurify_cjs () {
10417
11181
  the application unsanitized. Refuse to sanitize such a root
10418
11182
  the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
10419
11183
  if (_isClobbered(dirty)) {
11184
+ /* Fail closed on a live clobbered root before throwing.
11185
+ _neutralizeRoot's reads are clobber-safe (cached getters); the
11186
+ form's non-clobbered descendants, e.g. an armed <img>, are scrubbed. */
11187
+ _neutralizeRoot(dirty);
10420
11188
  throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
10421
11189
  }
10422
11190
  /* Sanitize attached shadow roots before the main iterator runs.
@@ -10469,20 +11237,24 @@ function requirePurify_cjs () {
10469
11237
  _forceRemove(body.firstChild);
10470
11238
  }
10471
11239
  /* Get node iterator */
10472
- const nodeIterator = _createNodeIterator(inPlace ? dirty : body);
11240
+ const walkRoot = inPlace ? dirty : body;
10473
11241
  /* Now start iterating over the created document.
10474
11242
  The walk runs inside an exception barrier (campaign-3 F2): a re-entrant
10475
11243
  engine/custom-element mutation can detach a node mid-walk so
10476
11244
  `_forceRemove`'s parentless guard throws, aborting the loop. Without the
10477
11245
  barrier the caller's in-place tree would be left half-sanitized with the
10478
- unvisited tail still armed. On any throw we fail closed — strip the
10479
- in-place root bare — then rethrow so the existing throw contract is
10480
- preserved. (String/DOM-copy paths never return the partial body, so the
10481
- propagating throw is already fail-closed there.) */
11246
+ unvisited tail still armed. _createNodeIterator itself is inside the
11247
+ barrier too: constructing the iterator dereferences the root's document,
11248
+ and any failure there (e.g. an exotic/clobbered root) must still fail
11249
+ closed rather than skip the neutralize. On any throw we fail closed -
11250
+ strip the in-place root bare - then rethrow so the existing throw
11251
+ contract is preserved. (String/DOM-copy paths never return the partial
11252
+ body, so the propagating throw is already fail-closed there.) */
10482
11253
  try {
11254
+ const nodeIterator = _createNodeIterator(walkRoot);
10483
11255
  while (currentNode = nodeIterator.nextNode()) {
10484
11256
  /* Sanitize tags and elements */
10485
- _sanitizeElements(currentNode);
11257
+ _sanitizeElements(currentNode, walkRoot);
10486
11258
  /* Check attributes next */
10487
11259
  _sanitizeAttributes(currentNode);
10488
11260
  /* Shadow DOM detected, sanitize it.
@@ -10496,6 +11268,14 @@ function requirePurify_cjs () {
10496
11268
  } catch (error) {
10497
11269
  if (inPlace) {
10498
11270
  _neutralizeRoot(dirty);
11271
+ /* Nodes _forceRemove'd earlier in the aborted walk are already
11272
+ detached from the root, so _neutralizeRoot's subtree pass does not
11273
+ reach them. Defuse them too, mirroring the success-path loop below. */
11274
+ arrayForEach(DOMPurify.removed, entry => {
11275
+ if (entry.element) {
11276
+ _neutralizeSubtree(entry.element);
11277
+ }
11278
+ });
10499
11279
  }
10500
11280
  throw error;
10501
11281
  }
@@ -14922,6 +15702,54 @@ var MultiWidget = /*#__PURE__*/function () {
14922
15702
  validate_card_types: validateCardNumberInput
14923
15703
  });
14924
15704
  }
15705
+ /**
15706
+ * Current method restricts which card schemes the card number input accepts, without changing which card
15707
+ * icons the widget displays. Scheme identifiers are matched case-insensitively and ignoring surrounding
15708
+ * whitespace; unsupported identifiers are ignored with a warning, so a list in which every identifier is
15709
+ * unsupported applies no restriction at all.
15710
+ *
15711
+ * Takes precedence over setSupportedCardIcons: when a non-empty list is supplied here, it is the only list
15712
+ * used for validation and the validateCardNumberInput flag of setSupportedCardIcons no longer affects it.
15713
+ * Calling this method more than once replaces the previous list rather than merging with it.
15714
+ *
15715
+ * Must be called before load().
15716
+ *
15717
+ * @example
15718
+ *
15719
+ * widget.setAllowedCardSchemes(['visa', 'mastercard']);
15720
+ *
15721
+ * @param {string[]} schemes - [CARD_SCHEME]{@link CARD_SCHEME}
15722
+ */
15723
+ }, {
15724
+ key: "setAllowedCardSchemes",
15725
+ value: function setAllowedCardSchemes(schemes) {
15726
+ var vocabulary = ObjectHelper.values(CARD_SCHEME);
15727
+ var allowedSchemes = [];
15728
+ var _iterator = _createForOfIteratorHelper(Array.isArray(schemes) ? schemes : []),
15729
+ _step;
15730
+ try {
15731
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
15732
+ var entry = _step.value;
15733
+ var scheme = typeof entry === 'string' ? entry.trim().toLowerCase() : '';
15734
+ if (vocabulary.indexOf(scheme) === -1) {
15735
+ console.warn("Widget::setAllowedCardSchemes: unsupported card scheme ".concat(entry));
15736
+ continue;
15737
+ }
15738
+ if (allowedSchemes.indexOf(scheme) === -1) {
15739
+ allowedSchemes.push(scheme);
15740
+ }
15741
+ }
15742
+ } catch (err) {
15743
+ _iterator.e(err);
15744
+ } finally {
15745
+ _iterator.f();
15746
+ }
15747
+ if (allowedSchemes.length) {
15748
+ this.link.setParams({
15749
+ allowed_card_schemes: allowedSchemes.join(',')
15750
+ });
15751
+ }
15752
+ }
14925
15753
  /**
14926
15754
  * Current method can hide prevent the widget from showing the error messages
14927
15755
  *
@@ -45282,14 +46110,17 @@ var dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; };
45282
46110
  var slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); };
45283
46111
  // read zip header
45284
46112
  var zh = function (d, b, z) {
45285
- var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);
45286
- var _a = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];
45287
- return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];
46113
+ var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);
46114
+ var _a = z && bs == 4294967295 ? z64e(d, es, efl) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];
46115
+ return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
45288
46116
  };
45289
46117
  // read zip64 extra field
45290
- var z64e = function (d, b) {
45291
- for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))
45292
- ;
46118
+ var z64e = function (d, b, l) {
46119
+ var e = b + l;
46120
+ for (; b2(d, b) != 1; b += 4 + b2(d, b + 2)) {
46121
+ if (b + 4 > e)
46122
+ err(13);
46123
+ }
45293
46124
  return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];
45294
46125
  };
45295
46126
  // extra field length
@@ -45892,7 +46723,7 @@ var Unzip = /*#__PURE__*/ (function () {
45892
46723
  var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);
45893
46724
  var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);
45894
46725
  if (sc_1 == 4294967295) {
45895
- _a = dd ? [-2] : z64e(buf, i), sc_1 = _a[0], su_1 = _a[1];
46726
+ _a = dd ? [-2] : z64e(buf, i, es), sc_1 = _a[0], su_1 = _a[1];
45896
46727
  }
45897
46728
  else if (dd)
45898
46729
  sc_1 = -1;
@@ -46167,4 +46998,4 @@ var browser = /*#__PURE__*/Object.freeze({
46167
46998
  zlibSync: zlibSync
46168
46999
  });
46169
47000
 
46170
- export { AfterpayCheckoutButton, AfterpayOnSiteMessaging, Api, ApplePayOpenWalletButton, ApplePayWalletButtonExpress, CANVAS_3DS_EVENT, CHECKOUT_BUTTON_EVENT, EVENT$3 as CHECKOUT_EVENT, Canvas3ds, Canvas3dsTokenFormat, Checkout, ClickToPay, Configuration, ContactShippingEditingMode, ELEMENT, ERROR_OPERATION, EVENT$5 as EVENT, Builder$1 as ExternalCheckoutBuilder, Checker as ExternalCheckoutChecker, FORM_FIELD$1 as FORM_FIELD, FRAUD_PREVENTION_EVENTS, FraudPreventionService, GooglePayOpenWalletButton, HtmlMultiWidget, HtmlPaymentSourceWidget, HtmlWidget, InstructionDebugger, MultiWidget, PAYMENT_EXPIRED, PAYMENT_FAILURE, PAYMENT_SUCCESSFUL, PAYMENT_TYPE, PURPOSE, PayPalDataCollector, PayPalSavePaymentSourceWidget, Builder as PaymentSourceBuilder, PaymentSourceWidget, PaypalCheckoutButton, PaypalWalletButtonExpress, STYLABLE_ELEMENT, STYLABLE_ELEMENT_STATE, STYLE$2 as STYLE, SUPPORTED_CARD_TYPES, TEXT, TOKEN_TYPE, TRIGGER$1 as TRIGGER, TYPE, VAULT_DISPLAY_STYLE, VaultDisplayWidget, EVENT as WALLET_BUTTONS_EXPRESS_EVENT, WALLET_TYPES, WalletButtons, ZipmoneyCheckoutButton };
47001
+ export { AfterpayCheckoutButton, AfterpayOnSiteMessaging, Api, ApplePayOpenWalletButton, ApplePayWalletButtonExpress, CANVAS_3DS_EVENT, CARD_SCHEME, CHECKOUT_BUTTON_EVENT, EVENT$3 as CHECKOUT_EVENT, Canvas3ds, Canvas3dsTokenFormat, Checkout, ClickToPay, Configuration, ContactShippingEditingMode, ELEMENT, ERROR_OPERATION, EVENT$5 as EVENT, Builder$1 as ExternalCheckoutBuilder, Checker as ExternalCheckoutChecker, FORM_FIELD$1 as FORM_FIELD, FRAUD_PREVENTION_EVENTS, FraudPreventionService, GooglePayOpenWalletButton, HtmlMultiWidget, HtmlPaymentSourceWidget, HtmlWidget, InstructionDebugger, MultiWidget, PAYMENT_EXPIRED, PAYMENT_FAILURE, PAYMENT_SUCCESSFUL, PAYMENT_TYPE, PURPOSE, PayPalDataCollector, PayPalSavePaymentSourceWidget, Builder as PaymentSourceBuilder, PaymentSourceWidget, PaypalCheckoutButton, PaypalWalletButtonExpress, STYLABLE_ELEMENT, STYLABLE_ELEMENT_STATE, STYLE$2 as STYLE, SUPPORTED_CARD_TYPES, TEXT, TOKEN_TYPE, TRIGGER$1 as TRIGGER, TYPE, VAULT_DISPLAY_STYLE, VaultDisplayWidget, EVENT as WALLET_BUTTONS_EXPRESS_EVENT, WALLET_TYPES, WalletButtons, ZipmoneyCheckoutButton };