braintree-web
Version:
A suite of tools for integrating Braintree in the browser
1,559 lines (1,396 loc) • 56 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.braintree || (g.braintree = {})).applePay = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromiseGlobal = void 0;
var promise_polyfill_1 = __importDefault(_dereq_("promise-polyfill"));
var PromiseGlobal =
// eslint-disable-next-line no-undef
typeof Promise !== "undefined" ? Promise : promise_polyfill_1.default;
exports.PromiseGlobal = PromiseGlobal;
},{"promise-polyfill":9}],2:[function(_dereq_,module,exports){
"use strict";
var promise_1 = _dereq_("./lib/promise");
var scriptPromiseCache = {};
function loadScript(options) {
var scriptLoadPromise;
var stringifiedOptions = JSON.stringify(options);
if (!options.forceScriptReload) {
scriptLoadPromise = scriptPromiseCache[stringifiedOptions];
if (scriptLoadPromise) {
return scriptLoadPromise;
}
}
var script = document.createElement("script");
var attrs = options.dataAttributes || {};
var container = options.container || document.head;
script.src = options.src;
script.id = options.id || "";
script.async = true;
if (options.crossorigin) {
script.setAttribute("crossorigin", "" + options.crossorigin);
}
Object.keys(attrs).forEach(function (key) {
script.setAttribute("data-" + key, "" + attrs[key]);
});
scriptLoadPromise = new promise_1.PromiseGlobal(function (resolve, reject) {
script.addEventListener("load", function () {
resolve(script);
});
script.addEventListener("error", function () {
reject(new Error(options.src + " failed to load."));
});
script.addEventListener("abort", function () {
reject(new Error(options.src + " has aborted."));
});
container.appendChild(script);
});
scriptPromiseCache[stringifiedOptions] = scriptLoadPromise;
return scriptLoadPromise;
}
loadScript.clearCache = function () {
scriptPromiseCache = {};
};
module.exports = loadScript;
},{"./lib/promise":1}],3:[function(_dereq_,module,exports){
module.exports = _dereq_("./dist/load-script");
},{"./dist/load-script":2}],4:[function(_dereq_,module,exports){
"use strict";
var GlobalPromise = (typeof Promise !== "undefined"
? Promise // eslint-disable-line no-undef
: null);
var ExtendedPromise = /** @class */ (function () {
function ExtendedPromise(options) {
var _this = this;
if (typeof options === "function") {
this._promise = new ExtendedPromise.Promise(options);
return;
}
this._promise = new ExtendedPromise.Promise(function (resolve, reject) {
_this._resolveFunction = resolve;
_this._rejectFunction = reject;
});
options = options || {};
this._onResolve = options.onResolve || ExtendedPromise.defaultOnResolve;
this._onReject = options.onReject || ExtendedPromise.defaultOnReject;
if (ExtendedPromise.shouldCatchExceptions(options)) {
this._promise.catch(function () {
// prevents unhandled promise rejection warning
// in the console for extended promises that
// that catch the error in an asynchronous manner
});
}
this._resetState();
}
ExtendedPromise.defaultOnResolve = function (result) {
return ExtendedPromise.Promise.resolve(result);
};
ExtendedPromise.defaultOnReject = function (err) {
return ExtendedPromise.Promise.reject(err);
};
ExtendedPromise.setPromise = function (PromiseClass) {
ExtendedPromise.Promise = PromiseClass;
};
ExtendedPromise.shouldCatchExceptions = function (options) {
if (options.hasOwnProperty("suppressUnhandledPromiseMessage")) {
return Boolean(options.suppressUnhandledPromiseMessage);
}
return Boolean(ExtendedPromise.suppressUnhandledPromiseMessage);
};
// start Promise methods documented in:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Methods
ExtendedPromise.all = function (args) {
return ExtendedPromise.Promise.all(args);
};
ExtendedPromise.allSettled = function (args) {
return ExtendedPromise.Promise.allSettled(args);
};
ExtendedPromise.race = function (args) {
return ExtendedPromise.Promise.race(args);
};
ExtendedPromise.reject = function (arg) {
return ExtendedPromise.Promise.reject(arg);
};
ExtendedPromise.resolve = function (arg) {
return ExtendedPromise.Promise.resolve(arg);
};
ExtendedPromise.prototype.then = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return (_a = this._promise).then.apply(_a, args);
};
ExtendedPromise.prototype.catch = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return (_a = this._promise).catch.apply(_a, args);
};
ExtendedPromise.prototype.resolve = function (arg) {
var _this = this;
if (this.isFulfilled) {
return this;
}
this._setResolved();
ExtendedPromise.Promise.resolve()
.then(function () {
return _this._onResolve(arg);
})
.then(function (argForResolveFunction) {
_this._resolveFunction(argForResolveFunction);
})
.catch(function (err) {
_this._resetState();
_this.reject(err);
});
return this;
};
ExtendedPromise.prototype.reject = function (arg) {
var _this = this;
if (this.isFulfilled) {
return this;
}
this._setRejected();
ExtendedPromise.Promise.resolve()
.then(function () {
return _this._onReject(arg);
})
.then(function (result) {
_this._setResolved();
_this._resolveFunction(result);
})
.catch(function (err) {
return _this._rejectFunction(err);
});
return this;
};
ExtendedPromise.prototype._resetState = function () {
this.isFulfilled = false;
this.isResolved = false;
this.isRejected = false;
};
ExtendedPromise.prototype._setResolved = function () {
this.isFulfilled = true;
this.isResolved = true;
this.isRejected = false;
};
ExtendedPromise.prototype._setRejected = function () {
this.isFulfilled = true;
this.isResolved = false;
this.isRejected = true;
};
ExtendedPromise.Promise = GlobalPromise;
return ExtendedPromise;
}());
module.exports = ExtendedPromise;
},{}],5:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function deferred(fn) {
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
setTimeout(function () {
try {
fn.apply(void 0, args);
}
catch (err) {
/* eslint-disable no-console */
console.log("Error in callback function");
console.log(err);
/* eslint-enable no-console */
}
}, 1);
};
}
exports.deferred = deferred;
},{}],6:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function once(fn) {
var called = false;
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!called) {
called = true;
fn.apply(void 0, args);
}
};
}
exports.once = once;
},{}],7:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable consistent-return */
function promiseOrCallback(promise, callback) {
if (!callback) {
return promise;
}
promise.then(function (data) { return callback(null, data); }).catch(function (err) { return callback(err); });
}
exports.promiseOrCallback = promiseOrCallback;
},{}],8:[function(_dereq_,module,exports){
"use strict";
var deferred_1 = _dereq_("./lib/deferred");
var once_1 = _dereq_("./lib/once");
var promise_or_callback_1 = _dereq_("./lib/promise-or-callback");
function wrapPromise(fn) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var callback;
var lastArg = args[args.length - 1];
if (typeof lastArg === "function") {
callback = args.pop();
callback = once_1.once(deferred_1.deferred(callback));
}
// I know, I know, this looks bad. But it's a quirk of the library that
// we need to allow passing the this context to the original function
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore: this has an implicit any
return promise_or_callback_1.promiseOrCallback(fn.apply(this, args), callback); // eslint-disable-line no-invalid-this
};
}
wrapPromise.wrapPrototype = function (target, options) {
if (options === void 0) { options = {}; }
var ignoreMethods = options.ignoreMethods || [];
var includePrivateMethods = options.transformPrivateMethods === true;
var methods = Object.getOwnPropertyNames(target.prototype).filter(function (method) {
var isNotPrivateMethod;
var isNonConstructorFunction = method !== "constructor" &&
typeof target.prototype[method] === "function";
var isNotAnIgnoredMethod = ignoreMethods.indexOf(method) === -1;
if (includePrivateMethods) {
isNotPrivateMethod = true;
}
else {
isNotPrivateMethod = method.charAt(0) !== "_";
}
return (isNonConstructorFunction && isNotPrivateMethod && isNotAnIgnoredMethod);
});
methods.forEach(function (method) {
var original = target.prototype[method];
target.prototype[method] = wrapPromise(original);
});
return target;
};
module.exports = wrapPromise;
},{"./lib/deferred":5,"./lib/once":6,"./lib/promise-or-callback":7}],9:[function(_dereq_,module,exports){
'use strict';
/**
* @this {Promise}
*/
function finallyConstructor(callback) {
var constructor = this.constructor;
return this.then(
function(value) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
// @ts-ignore
return constructor.reject(reason);
});
}
);
}
function allSettled(arr) {
var P = this;
return new P(function(resolve, reject) {
if (!(arr && typeof arr.length !== 'undefined')) {
return reject(
new TypeError(
typeof arr +
' ' +
arr +
' is not iterable(cannot read property Symbol(Symbol.iterator))'
)
);
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
function(e) {
args[i] = { status: 'rejected', reason: e };
if (--remaining === 0) {
resolve(args);
}
}
);
return;
}
}
args[i] = { status: 'fulfilled', value: val };
if (--remaining === 0) {
resolve(args);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
}
// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;
function isArray(x) {
return Boolean(x && typeof x.length !== 'undefined');
}
function noop() {}
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
};
}
/**
* @constructor
* @param {Function} fn
*/
function Promise(fn) {
if (!(this instanceof Promise))
throw new TypeError('Promises must be constructed via new');
if (typeof fn !== 'function') throw new TypeError('not a function');
/** @type {!number} */
this._state = 0;
/** @type {!boolean} */
this._handled = false;
/** @type {Promise|undefined} */
this._value = undefined;
/** @type {!Array<!Function>} */
this._deferreds = [];
doResolve(fn, this);
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise._immediateFn(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
}
function resolve(self, newValue) {
try {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self)
throw new TypeError('A promise cannot be resolved with itself.');
if (
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise._immediateFn(function() {
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
/**
* @constructor
*/
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, self) {
var done = false;
try {
fn(
function(value) {
if (done) return;
done = true;
resolve(self, value);
},
function(reason) {
if (done) return;
done = true;
reject(self, reason);
}
);
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
}
Promise.prototype['catch'] = function(onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
// @ts-ignore
var prom = new this.constructor(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.prototype['finally'] = finallyConstructor;
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError('Promise.all accepts an array'));
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.allSettled = allSettled;
Promise.resolve = function(value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError('Promise.race accepts an array'));
}
for (var i = 0, len = arr.length; i < len; i++) {
Promise.resolve(arr[i]).then(resolve, reject);
}
});
};
// Use polyfill for setImmediate for performance gains
Promise._immediateFn =
// @ts-ignore
(typeof setImmediate === 'function' &&
function(fn) {
// @ts-ignore
setImmediate(fn);
}) ||
function(fn) {
setTimeoutFunc(fn, 0);
};
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== 'undefined' && console) {
console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
}
};
module.exports = Promise;
},{}],10:[function(_dereq_,module,exports){
"use strict";
var BraintreeError = _dereq_("../lib/braintree-error");
var analytics = _dereq_("../lib/analytics");
var errors = _dereq_("./errors");
var Promise = _dereq_("../lib/promise");
var methods = _dereq_("../lib/methods");
var convertMethodsToError = _dereq_("../lib/convert-methods-to-error");
var wrapPromise = _dereq_("@braintree/wrap-promise");
/**
* @typedef {object} ApplePay~tokenizePayload
* @property {string} nonce The payment method nonce.
* @property {object} details Additional details.
* @property {string} details.cardType Type of card, ex: Visa, MasterCard.
* @property {string} details.cardHolderName The name of the card holder.
* @property {string} details.dpanLastTwo Last two digits of card number.
* @property {string} description A human-readable description.
* @property {string} type The payment method type, always `ApplePayCard`.
* @property {object} binData Information about the card based on the bin.
* @property {string} binData.commercial Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.countryOfIssuance The country of issuance.
* @property {string} binData.debit Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.durbinRegulated Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.healthcare Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.issuingBank The issuing bank.
* @property {string} binData.payroll Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.prepaid Possible values: 'Yes', 'No', 'Unknown'.
* @property {string} binData.productId The product id.
*/
/**
* An Apple Pay Payment Authorization Event object.
* @typedef {object} ApplePayPaymentAuthorizedEvent
* @external ApplePayPaymentAuthorizedEvent
* @see {@link https://developer.apple.com/reference/applepayjs/applepaypaymentauthorizedevent ApplePayPaymentAuthorizedEvent}
*/
/**
* An Apple Pay Payment Request object.
* @typedef {object} ApplePayPaymentRequest
* @external ApplePayPaymentRequest
* @see {@link https://developer.apple.com/reference/applepayjs/1916082-applepay_js_data_types/paymentrequest PaymentRequest}
*/
/**
* @class
* @param {object} options Options
* @description <strong>You cannot use this constructor directly. Use {@link module:braintree-web/apple-pay.create|braintree.applePay.create} instead.</strong>
* @classdesc This class represents an Apple Pay component. Instances of this class have methods for validating the merchant server and tokenizing payments.
*/
function ApplePay(options) {
this._instantiatedWithClient = Boolean(!options.useDeferredClient);
this._client = options.client;
this._createPromise = options.createPromise;
if (this._client) {
this._setMerchantIdentifier();
}
}
ApplePay.prototype._waitForClient = function () {
if (this._client) {
return Promise.resolve();
}
return this._createPromise.then(
function (client) {
this._client = client;
this._setMerchantIdentifier();
}.bind(this)
);
};
ApplePay.prototype._setMerchantIdentifier = function () {
var applePayConfig =
this._client.getConfiguration().gatewayConfiguration.applePayWeb;
if (!applePayConfig) {
return;
}
/**
* @name ApplePay#merchantIdentifier
* @description A special merchant ID which represents the merchant association with Braintree. Required when using `ApplePaySession.canMakePaymentsWithActiveCard`.
* @example
* var promise = ApplePaySession.canMakePaymentsWithActiveCard(applePayInstance.merchantIdentifier);
* promise.then(function (canMakePaymentsWithActiveCard) {
* if (canMakePaymentsWithActiveCard) {
* // Set up Apple Pay buttons
* }
* });
*/
Object.defineProperty(this, "merchantIdentifier", {
value: applePayConfig.merchantIdentifier,
configurable: false,
writable: false,
});
};
/**
* Merges a payment request with Braintree defaults to return an {external:ApplePayPaymentRequest}.
*
* The following properties are assigned to `paymentRequest` if not already defined. Their default values come from the Braintree gateway.
* - `countryCode`
* - `currencyCode`
* - `merchantCapabilities`
* - `supportedNetworks`
* @public
* @param {external:ApplePayPaymentRequest} paymentRequest The payment request details to apply on top of those from Braintree.
* @returns {external:ApplePayPaymentRequest|Promise} The decorated `paymentRequest` object. If `useDeferredClient` is used along with an `authorization`, this method will return a promise that resolves with the `paymentRequest` object.
* @example
* var applePay = require('braintree-web/apple-pay');
*
* applePay.create({client: clientInstance}, function (applePayErr, applePayInstance) {
* if (applePayErr) {
* // Handle error here
* return;
* }
*
* var paymentRequest = applePayInstance.createPaymentRequest({
* total: {
* label: 'My Company',
* amount: '19.99'
* }
* });
*
* var session = new ApplePaySession(3, paymentRequest);
*
* // ...
* @example <caption>With deferred client</caption>
* var applePay = require('braintree-web/apple-pay');
*
* applePay.create({
* authorization: 'client-token-or-tokenization-key',
* useDeferredClient: true
* }, function (applePayErr, applePayInstance) {
* if (applePayErr) {
* // Handle error here
* return;
* }
*
* applePayInstance.createPaymentRequest({
* total: {
* label: 'My Company',
* amount: '19.99'
* }
* }).then(function (paymentRequest) {
* var session = new ApplePaySession(3, paymentRequest);
*
* // ...
* });
*/
ApplePay.prototype.createPaymentRequest = function (paymentRequest) {
if (this._instantiatedWithClient) {
return this._createPaymentRequestSynchronously(paymentRequest);
}
return this._waitForClient().then(
function () {
return this._createPaymentRequestSynchronously(paymentRequest);
}.bind(this)
);
};
ApplePay.prototype._createPaymentRequestSynchronously = function (
paymentRequest
) {
var applePay =
this._client.getConfiguration().gatewayConfiguration.applePayWeb;
var defaults = {
countryCode: applePay.countryCode,
currencyCode: applePay.currencyCode,
merchantCapabilities: applePay.merchantCapabilities || ["supports3DS"],
supportedNetworks: applePay.supportedNetworks.map(function (network) {
return network === "mastercard" ? "masterCard" : network;
}),
};
return Object.assign({}, defaults, paymentRequest);
};
/**
* Validates your merchant website, as required by `ApplePaySession` before payment can be authorized.
* @public
* @param {object} options Options
* @param {string} options.validationURL The validationURL from an `ApplePayValidateMerchantEvent`.
* @param {string} options.displayName The canonical name for your store. Use a non-localized name. This parameter should be a UTF-8 string that is a maximum of 128 characters. The system may display this name to the user.
* @param {callback} [callback] The second argument, <code>data</code>, is the Apple Pay merchant session object. If no callback is provided, `performValidation` returns a promise.
* Pass the merchant session to your Apple Pay session's `completeMerchantValidation` method.
* @returns {(Promise|void)} Returns a promise if no callback is provided.
* @example
* var applePay = require('braintree-web/apple-pay');
*
* applePay.create({client: clientInstance}, function (applePayErr, applePayInstance) {
* if (applePayErr) {
* // Handle error here
* return;
* }
*
* var paymentRequest = applePayInstance.createPaymentRequest({
* total: {
* label: 'My Company',
* amount: '19.99'
* }
* });
* var session = new ApplePaySession(3, paymentRequest);
*
* session.onvalidatemerchant = function (event) {
* applePayInstance.performValidation({
* validationURL: event.validationURL,
* displayName: 'My Great Store'
* }, function (validationErr, validationData) {
* if (validationErr) {
* console.error(validationErr);
* session.abort();
* return;
* }
*
* session.completeMerchantValidation(validationData);
* });
* };
* });
*/
ApplePay.prototype.performValidation = function (options) {
var self = this;
if (!options || !options.validationURL) {
return Promise.reject(
new BraintreeError(errors.APPLE_PAY_VALIDATION_URL_REQUIRED)
);
}
return this._waitForClient()
.then(function () {
var applePayWebSession = {
validationUrl: options.validationURL,
domainName: options.domainName || window.location.hostname,
merchantIdentifier:
options.merchantIdentifier || self.merchantIdentifier,
};
if (options.displayName != null) {
applePayWebSession.displayName = options.displayName;
}
return self._client.request({
method: "post",
endpoint: "apple_pay_web/sessions",
data: {
_meta: { source: "apple-pay" },
applePayWebSession: applePayWebSession,
},
});
})
.then(function (response) {
analytics.sendEvent(self._client, "applepay.performValidation.succeeded");
return Promise.resolve(response);
})
.catch(function (err) {
analytics.sendEvent(self._client, "applepay.performValidation.failed");
if (err.code === "CLIENT_REQUEST_ERROR") {
return Promise.reject(
new BraintreeError({
type: errors.APPLE_PAY_MERCHANT_VALIDATION_FAILED.type,
code: errors.APPLE_PAY_MERCHANT_VALIDATION_FAILED.code,
message: errors.APPLE_PAY_MERCHANT_VALIDATION_FAILED.message,
details: {
originalError: err.details.originalError,
},
})
);
}
return Promise.reject(
new BraintreeError({
type: errors.APPLE_PAY_MERCHANT_VALIDATION_NETWORK.type,
code: errors.APPLE_PAY_MERCHANT_VALIDATION_NETWORK.code,
message: errors.APPLE_PAY_MERCHANT_VALIDATION_NETWORK.message,
details: {
originalError: err,
},
})
);
});
};
/**
* Tokenizes an Apple Pay payment. This will likely be called in your `ApplePaySession`'s `onpaymentauthorized` callback.
* @public
* @param {object} options Options
* @param {object} options.token The `payment.token` property of an {@link external:ApplePayPaymentAuthorizedEvent}.
* @param {callback} [callback] The second argument, <code>data</code>, is a {@link ApplePay~tokenizePayload|tokenizePayload}. If no callback is provided, `tokenize` returns a promise that resolves with a {@link ApplePay~tokenizePayload|tokenizePayload}.
* @returns {(Promise|void)} Returns a promise if no callback is provided.
* @example
* var applePay = require('braintree-web/apple-pay');
*
* applePay.create({client: clientInstance}, function (applePayErr, applePayInstance) {
* if (applePayErr) {
* // Handle error here
* return;
* }
*
* var paymentRequest = applePayInstance.createPaymentRequest({
* total: {
* label: 'My Company',
* amount: '19.99'
* }
* });
* var session = new ApplePaySession(3, paymentRequest);
*
* session.onpaymentauthorized = function (event) {
* applePayInstance.tokenize({
* token: event.payment.token
* }, function (tokenizeErr, tokenizedPayload) {
* if (tokenizeErr) {
* session.completePayment(ApplePaySession.STATUS_FAILURE);
* return;
* }
* // Send the tokenizedPayload to your server here!
*
* // Once the transaction is complete, call completePayment
* // to close the Apple Pay sheet
* session.completePayment(ApplePaySession.STATUS_SUCCESS);
* });
* };
*
* // ...
* });
*/
ApplePay.prototype.tokenize = function (options) {
var self = this;
if (!options.token) {
return Promise.reject(
new BraintreeError(errors.APPLE_PAY_PAYMENT_TOKEN_REQUIRED)
);
}
return this._waitForClient()
.then(function () {
return self._client.request({
method: "post",
endpoint: "payment_methods/apple_payment_tokens",
data: {
_meta: {
source: "apple-pay",
},
applePaymentToken: Object.assign({}, options.token, {
// The gateway requires this key to be base64-encoded.
paymentData: btoa(JSON.stringify(options.token.paymentData)),
}),
},
});
})
.then(function (response) {
analytics.sendEvent(self._client, "applepay.tokenize.succeeded");
return Promise.resolve(response.applePayCards[0]);
})
.catch(function (err) {
analytics.sendEvent(self._client, "applepay.tokenize.failed");
return Promise.reject(
new BraintreeError({
type: errors.APPLE_PAY_TOKENIZATION.type,
code: errors.APPLE_PAY_TOKENIZATION.code,
message: errors.APPLE_PAY_TOKENIZATION.message,
details: {
originalError: err,
},
})
);
});
};
/**
* Cleanly tear down anything set up by {@link module:braintree-web/apple-pay.create|create}.
* @public
* @param {callback} [callback] Called once teardown is complete. No data is returned if teardown completes successfully.
* @example
* applePayInstance.teardown();
* @example <caption>With callback</caption>
* applePayInstance.teardown(function () {
* // teardown is complete
* });
* @returns {(Promise|void)} Returns a promise if no callback is provided.
*/
ApplePay.prototype.teardown = function () {
convertMethodsToError(this, methods(ApplePay.prototype));
return Promise.resolve();
};
module.exports = wrapPromise.wrapPrototype(ApplePay);
},{"../lib/analytics":14,"../lib/braintree-error":17,"../lib/convert-methods-to-error":19,"../lib/methods":26,"../lib/promise":27,"./errors":11,"@braintree/wrap-promise":8}],11:[function(_dereq_,module,exports){
"use strict";
/**
* @name BraintreeError.Apple Pay - Creation Error Codes
* @description Errors that occur when [creating the Apple Pay component](./module-braintree-web_apple-pay.html#.create).
* @property {MERCHANT} APPLE_PAY_NOT_ENABLED Occurs when the authorization used is not authorized to process Apple Pay.
*/
/**
* @name BraintreeError.Apple Pay - performValidation Error Codes
* @description Errors that occur when [validating](./ApplePay.html#performValidation).
* @property {MERCHANT} APPLE_PAY_VALIDATION_URL_REQUIRED Occurs when the `validationURL` option is not passed in.
* @property {MERCHANT} APPLE_PAY_MERCHANT_VALIDATION_FAILED Occurs when the website domain has not been registered in the Braintree control panel.
* @property {NETWORK} APPLE_PAY_MERCHANT_VALIDATION_NETWORK Occurs when an unknown network error occurs.
*/
/**
* @name BraintreeError.Apple Pay - tokenize Error Codes
* @description Errors that occur when [tokenizing](./ApplePay.html#tokenize).
* @property {MERCHANT} APPLE_PAY_PAYMENT_TOKEN_REQUIRED Occurs when the `token` option is not passed in.
* @property {NETWORK} APPLE_PAY_TOKENIZATION Occurs when an unknown network error occurs.
*/
var BraintreeError = _dereq_("../lib/braintree-error");
module.exports = {
APPLE_PAY_NOT_ENABLED: {
type: BraintreeError.types.MERCHANT,
code: "APPLE_PAY_NOT_ENABLED",
message: "Apple Pay is not enabled for this merchant.",
},
APPLE_PAY_VALIDATION_URL_REQUIRED: {
type: BraintreeError.types.MERCHANT,
code: "APPLE_PAY_VALIDATION_URL_REQUIRED",
message: "performValidation must be called with a validationURL.",
},
APPLE_PAY_MERCHANT_VALIDATION_NETWORK: {
type: BraintreeError.types.NETWORK,
code: "APPLE_PAY_MERCHANT_VALIDATION_NETWORK",
message: "A network error occurred when validating the Apple Pay merchant.",
},
APPLE_PAY_MERCHANT_VALIDATION_FAILED: {
type: BraintreeError.types.MERCHANT,
code: "APPLE_PAY_MERCHANT_VALIDATION_FAILED",
message:
"Make sure you have registered your domain name in the Braintree Control Panel.",
},
APPLE_PAY_PAYMENT_TOKEN_REQUIRED: {
type: BraintreeError.types.MERCHANT,
code: "APPLE_PAY_PAYMENT_TOKEN_REQUIRED",
message: "tokenize must be called with a payment token.",
},
APPLE_PAY_TOKENIZATION: {
type: BraintreeError.types.NETWORK,
code: "APPLE_PAY_TOKENIZATION",
message: "A network error occurred when processing the Apple Pay payment.",
},
};
},{"../lib/braintree-error":17}],12:[function(_dereq_,module,exports){
"use strict";
/**
* @module braintree-web/apple-pay
* @description Accept Apple Pay on the Web. *This component is currently in beta and is subject to change.*
*/
var ApplePay = _dereq_("./apple-pay");
var analytics = _dereq_("../lib/analytics");
var BraintreeError = _dereq_("../lib/braintree-error");
var basicComponentVerification = _dereq_("../lib/basic-component-verification");
var createAssetsUrl = _dereq_("../lib/create-assets-url");
var createDeferredClient = _dereq_("../lib/create-deferred-client");
var Promise = _dereq_("../lib/promise");
var errors = _dereq_("./errors");
var VERSION = "3.87.0";
var wrapPromise = _dereq_("@braintree/wrap-promise");
/**
* @static
* @function create
* @param {object} options Creation options:
* @param {Client} [options.client] A {@link Client} instance.
* @param {string} [options.authorization] A tokenizationKey or clientToken. Can be used in place of `options.client`.
* @param {boolean} [options.useDeferredClient] Used in conjunction with `authorization`, allows the Apple Pay instance to be available right away by fetching the client configuration in the background. When this option is used, {@link ApplePay#createPaymentRequest} will return a promise that resolves with the configuration instead of returning synchronously.
* @param {callback} [callback] The second argument, `data`, is the {@link ApplePay} instance. If no callback is provided, `create` returns a promise that resolves with the {@link ApplePay} instance.
* @returns {(Promise|void)} Returns a promise if no callback is provided.
*/
function create(options) {
var name = "Apple Pay";
return basicComponentVerification
.verify({
name: name,
client: options.client,
authorization: options.authorization,
})
.then(function () {
var applePayInstance;
var createPromise = createDeferredClient
.create({
authorization: options.authorization,
client: options.client,
debug: options.debug,
assetsUrl: createAssetsUrl.create(options.authorization),
name: name,
})
.then(function (client) {
if (!client.getConfiguration().gatewayConfiguration.applePayWeb) {
return Promise.reject(
new BraintreeError(errors.APPLE_PAY_NOT_ENABLED)
);
}
analytics.sendEvent(client, "applepay.initialized");
return client;
});
options.createPromise = createPromise;
applePayInstance = new ApplePay(options);
if (!options.useDeferredClient) {
return createPromise.then(function (client) {
applePayInstance._client = client;
return applePayInstance;
});
}
return applePayInstance;
});
}
module.exports = {
create: wrapPromise(create),
/**
* @description The current version of the SDK, i.e. `{@pkg version}`.
* @type {string}
*/
VERSION: VERSION,
};
},{"../lib/analytics":14,"../lib/basic-component-verification":16,"../lib/braintree-error":17,"../lib/create-assets-url":20,"../lib/create-deferred-client":22,"../lib/promise":27,"./apple-pay":10,"./errors":11,"@braintree/wrap-promise":8}],13:[function(_dereq_,module,exports){
"use strict";
var createAuthorizationData = _dereq_("./create-authorization-data");
var jsonClone = _dereq_("./json-clone");
var constants = _dereq_("./constants");
function addMetadata(configuration, data) {
var key;
var attrs = data ? jsonClone(data) : {};
var authAttrs = createAuthorizationData(configuration.authorization).attrs;
var _meta = jsonClone(configuration.analyticsMetadata);
attrs.braintreeLibraryVersion = constants.BRAINTREE_LIBRARY_VERSION;
for (key in attrs._meta) {
if (attrs._meta.hasOwnProperty(key)) {
_meta[key] = attrs._meta[key];
}
}
attrs._meta = _meta;
if (authAttrs.tokenizationKey) {
attrs.tokenizationKey = authAttrs.tokenizationKey;
} else {
attrs.authorizationFingerprint = authAttrs.authorizationFingerprint;
}
return attrs;
}
module.exports = addMetadata;
},{"./constants":18,"./create-authorization-data":21,"./json-clone":25}],14:[function(_dereq_,module,exports){
"use strict";
var Promise = _dereq_("./promise");
var constants = _dereq_("./constants");
var addMetadata = _dereq_("./add-metadata");
function sendAnalyticsEvent(clientInstanceOrPromise, kind, callback) {
var timestamp = Date.now(); // milliseconds
return Promise.resolve(clientInstanceOrPromise)
.then(function (client) {
var timestampInPromise = Date.now();
var configuration = client.getConfiguration();
var request = client._request;
var url = configuration.gatewayConfiguration.analytics.url;
var data = {
analytics: [
{
kind: constants.ANALYTICS_PREFIX + kind,
isAsync:
Math.floor(timestampInPromise / 1000) !==
Math.floor(timestamp / 1000),
timestamp: timestamp,
},
],
};
request(
{
url: url,
method: "post",
data: addMetadata(configuration, data),
timeout: constants.ANALYTICS_REQUEST_TIMEOUT_MS,
},
callback
);
})
.catch(function (err) {
// for all non-test cases, we don't provide a callback,
// so this error will always be swallowed. In this case,
// that's fine, it should only error when the deferred
// client fails to set up, in which case we don't want
// that error to report over and over again via these
// deferred analytics events
if (callback) {
callback(err);
}
});
}
module.exports = {
sendEvent: sendAnalyticsEvent,
};
},{"./add-metadata":13,"./constants":18,"./promise":27}],15:[function(_dereq_,module,exports){
"use strict";
var loadScript = _dereq_("@braintree/asset-loader/load-script");
module.exports = {
loadScript: loadScript,
};
},{"@braintree/asset-loader/load-script":3}],16:[function(_dereq_,module,exports){
"use strict";
var BraintreeError = _dereq_("./braintree-error");
var Promise = _dereq_("./promise");
var sharedErrors = _dereq_("./errors");
var VERSION = "3.87.0";
function basicComponentVerification(options) {
var client, authorization, name;
if (!options) {
return Promise.reject(
new BraintreeError({
type: sharedErrors.INVALID_USE_OF_INTERNAL_FUNCTION.type,
code: sharedErrors.INVALID_USE_OF_INTERNAL_FUNCTION.code,
message:
"Options must be passed to basicComponentVerification function.",
})
);
}
name = options.name;
client = options.client;
authorization = options.authorization;
if (!client && !authorization) {
return Promise.reject(
new BraintreeError({
type: sharedErrors.INSTANTIATION_OPTION_REQUIRED.type,
code: sharedErrors.INSTANTIATION_OPTION_REQUIRED.code,
// NEXT_MAJOR_VERSION in major version, we expose passing in authorization for all components
// instead of passing in a client instance. Leave this a silent feature for now.
message: "options.client is required when instantiating " + name + ".",
})
);
}
if (!authorization && client.getVersion() !== VERSION) {
return Promise.reject(
new BraintreeError({
type: sharedErrors.INCOMPATIBLE_VERSIONS.type,
code: sharedErrors.INCOMPATIBLE_VERSIONS.code,
message:
"Client (version " +
client.getVersion() +
") and " +
name +
" (version " +
VERSION +
") components must be from the same SDK version.",
})
);
}
return Promise.resolve();
}
module.exports = {
verify: basicComponentVerification,
};
},{"./braintree-error":17,"./errors":24,"./promise":27}],17:[function(_dereq_,module,exports){
"use strict";
var enumerate = _dereq_("./enumerate");
/**
* @class
* @global
* @param {object} options Construction options
* @classdesc This class is used to report error conditions, frequently as the first parameter to callbacks throughout the Braintree SDK.
* @description <strong>You cannot use this constructor directly. Interact with instances of this class through {@link callback callbacks}.</strong>
*/
function BraintreeError(options) {
if (!BraintreeError.types.hasOwnProperty(options.type)) {
throw new Error(options.type + " is not a valid type.");
}
if (!options.code) {
throw new Error("Error code required.");
}
if (!options.message) {
throw new Error("Error message required.");
}
this.name = "BraintreeError";
/**
* @type {string}
* @description A code that corresponds to specific errors.
*/
this.code = options.code;
/**
* @type {string}
* @description A short description of the error.
*/
this.message = options.message;
/**
* @type {BraintreeError.types}
* @description The type of error.
*/
this.type = options.type;
/**
* @type {object=}
* @description Additional information about the error, such as an underlying network error response.
*/
this.details = options.details;
}
BraintreeError.prototype = Object.create(Error.prototype);
BraintreeError.prototype.constructor = BraintreeError;
/**
* Enum for {@link BraintreeError} types.
* @name BraintreeError.types
* @enum
* @readonly
* @memberof BraintreeError
* @property {string} CUSTOMER An error caused by the customer.
* @property {string} MERCHANT An error that is actionable by the merchant.
* @property {string} NETWORK An error due to a network problem.
* @property {string} INTERNAL An error caused by Braintree code.
* @property {string} UNKNOWN An error where the origin is unknown.
*/
BraintreeError.types = enumerate([
"CUSTOMER",
"MERCHANT",
"NETWORK",
"INTERNAL",
"UNKNOWN",
]);
BraintreeError.findRootError = function (err) {
if (
err instanceof BraintreeError &&
err.details &&
err.details.originalError
) {
return BraintreeError.findRootError(err.details.originalError);
}
return err;
};
module.exports = BraintreeError;
},{"./enumerate":23}],18:[function(_dereq_,module,exports){
"use strict";
var VERSION = "3.87.0";
var PLATFORM = "web";
var CLIENT_API_URLS = {
production: "https://api.braintreegateway.com:443",
sandbox: "https://api.sandbox.braintreegateway.com:443",
};
var ASSETS_URLS = {
production: "https://assets.braintreegateway.com",
sandbox: "https://assets.braintreegateway.com",
};
var GRAPHQL_URLS = {
production: "https://payments.braintree-api.com/graphql",
sandbox: "https://payments.sandbox.braintree-api.com/graphql",
};
// endRemoveIf(production)
module.exports = {
ANALYTICS_PREFIX: PLATFORM + ".",
ANALYTICS_REQUEST_TIMEOUT_MS: 2000,
ASSETS_URLS: ASSETS_URLS,
CLIENT_API_URLS: CLIENT_API_URLS,
FRAUDNET_SOURCE: "BRAINTREE_SIGNIN",
FRAUDNET_FNCLS: "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99",
FRAUDNET_URL: "https://c.paypal.com/da/r/fb.js",
BUS_CONFIGURATION_REQUEST_EVENT: "BUS_CONFIGURATION_REQUEST",
GRAPHQL_URLS: GRAPHQL_URLS,
INTEGRATION_TIMEOUT_MS: 60000,
VERSION: VERSION,
INTEGRATION: "custom",
SOURCE: "client",
PLATFORM: PLATFORM,
BRAINTREE_LIBRARY_VERSION: "braintree/" + PLATFORM + "/" + VERSION,
};
},{}],19:[function(_dereq_,module,exports){
"use strict";
var BraintreeError = _dereq_("./braintree-error");
var sharedErrors = _dereq_("./errors");
module.exports = function (instance, methodNames) {
methodNames.forEach(function (methodName) {
instance[methodName] = function () {
throw new BraintreeError({
type: sharedErrors.METHOD_CALLED_AFTER_TEARDOWN.type,
code: sharedErrors.METHOD_CALLED_AFTER_TEARDOWN.code,
message: methodName + " cannot be called after teardown.",
});
};
});
};
},{"./braintree-error":17,"./errors":24}],20:[function(_dereq_,module,exports){
"use strict";
// endRemoveIf(production)
var ASSETS_URLS = _dereq_("./constants").ASSETS_URLS;
function createAssetsUrl(authorization) {
// endRemoveIf(production)
return ASSETS_URLS.production;
}
/* eslint-enable */
module.exports = {
create: createAssetsUrl,
};
},{"./constants":18}],21:[function(_dereq_,module,exports){
"use strict";
var atob = _dereq_("../lib/vendor/polyfill").atob;
var CLIENT_API_URLS = _dereq_("../lib/constants").CLIENT_API_URLS;
function _isTokenizationKey(str) {
return /^[a-zA-Z0-9]+_[a-zA-Z0-9]+_[a-zA-Z0-9_]+$/.test(str);
}
function _parseTokenizationKey(tokenizationKey) {
var tokens = tokenizationKey.split("_");
var environment = tokens[0];
var merchantId = tokens.slice(2).join("_");
return {
merchantId: merchantId,
environment: environment,
};
}
function createAuthorizationData(authorization) {
var parsedClientToken, parsedTokenizationKey;
var data = {
attrs: {},
configUrl: "",
};
if (_isTokenizationKey(authorization)) {
parsedTokenizationKey = _parseTokenizationKey(authorization);
data.environment = parsedTokenizationKey.environment;
data.attrs.tokenizationKey = authorization;
data.configUrl =
CLIENT_API_URLS[parsedTokenizationKey.environment] +
"/merchants/" +
parsedTokenizationKey.merchantId +
"/client_api/v1/configuration";
} else {
parsedClientToken = JSON.parse(atob(authorization));
data.environment = parsedClientToken.environment;
data.attrs.authorizationFingerprint =
parsedClientToken.authorizationFingerprint;
data.configUrl = parsedClientToken.configUrl;
data.graphQL = parsedClientToken.graphQL;
}
return data;
}
module.exports = createAuthorizationData;
},{"../lib/constants":18,"../lib/vendor/polyfill":28}],22:[function(_dereq_,module,exports){
"use strict";
var BraintreeError = _dereq_("./braintree-error");
var Promise = _dereq_("./promise");
var assets = _dereq_("./assets");
var sharedErrors = _dereq_("./errors");
var VERSION = "3.87.0";
function createDeferredClient(options) {
var promise = Promise.resolve();
if (options.client) {
return