UNPKG

braintree-web

Version:

A suite of tools for integrating Braintree in the browser

1,477 lines (1,336 loc) 64.8 kB
(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 = {})).googlePayment = 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"; /** * @name BraintreeError.Google Payment - Creation Error Codes * @description Errors that occur when [creating the Google Payment component](./module-braintree-web_google-payment.html#.create). * @property {MERCHANT} GOOGLE_PAYMENT_NOT_ENABLED Occurs when Google Pay is not enabled on the Braintree control panel. * @property {MERCHANT} GOOGLE_PAYMENT_UNSUPPORTED_VERSION Occurs when a Google Pay version is used that is not supported by the Braintree SDK. */ /** * @name BraintreeError.Google Payment - parseResponse Error Codes * @description Errors that occur when [parsing the response from Google](./GooglePayment.html#parseResponse). * @property {UNKNOWN} GOOGLE_PAYMENT_GATEWAY_ERROR Occurs when Google Pay could not be tokenized. */ var BraintreeError = _dereq_("../lib/braintree-error"); module.exports = { GOOGLE_PAYMENT_NOT_ENABLED: { type: BraintreeError.types.MERCHANT, code: "GOOGLE_PAYMENT_NOT_ENABLED", message: "Google Pay is not enabled for this merchant.", }, GOOGLE_PAYMENT_GATEWAY_ERROR: { code: "GOOGLE_PAYMENT_GATEWAY_ERROR", message: "There was an error when tokenizing the Google Pay payment method.", type: BraintreeError.types.UNKNOWN, }, GOOGLE_PAYMENT_UNSUPPORTED_VERSION: { code: "GOOGLE_PAYMENT_UNSUPPORTED_VERSION", type: BraintreeError.types.MERCHANT, }, }; },{"../lib/braintree-error":18}],11:[function(_dereq_,module,exports){ "use strict"; var analytics = _dereq_("../lib/analytics"); var assign = _dereq_("../lib/assign").assign; var convertMethodsToError = _dereq_("../lib/convert-methods-to-error"); var find = _dereq_("../lib/find"); var generateGooglePayConfiguration = _dereq_("../lib/generate-google-pay-configuration"); var BraintreeError = _dereq_("../lib/braintree-error"); var errors = _dereq_("./errors"); var methods = _dereq_("../lib/methods"); var Promise = _dereq_("../lib/promise"); var wrapPromise = _dereq_("@braintree/wrap-promise"); var CREATE_PAYMENT_DATA_REQUEST_METHODS = { 1: "_createV1PaymentDataRequest", 2: "_createV2PaymentDataRequest", }; /** * @typedef {object} GooglePayment~tokenizePayload * @property {string} nonce The payment method nonce. * @property {object} details Additional account details. * @property {string} details.cardType Type of card, ex: Visa, MasterCard. * @property {string} details.lastFour Last four digits of card number. * @property {string} details.lastTwo Last two digits of card number. * @property {boolean} details.isNetworkTokenized True if the card is network tokenized. * @property {string} details.bin First six digits of card number. * @property {string} description A human-readable description. * @property {string} type The payment method type, `CreditCard` or `AndroidPayCard`. * @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. */ /** * @class GooglePayment * @param {object} options Google Payment {@link module:braintree-web/google-payment.create create} options. * @description <strong>Do not use this constructor directly. Use {@link module:braintree-web/google-payment.create|braintree-web.google-payment.create} instead.</strong> * @classdesc This class represents a Google Payment component produced by {@link module:braintree-web/google-payment.create|braintree-web/google-payment.create}. Instances of this class have methods for initializing the Google Pay flow. */ function GooglePayment(options) { this._createPromise = options.createPromise; this._client = options.client; this._useDeferredClient = options.useDeferredClient; // NEXT_MAJOR_VERSION this should be updated to 2 (or whatever the current latest version is) this._googlePayVersion = options.googlePayVersion || 1; this._googleMerchantId = options.googleMerchantId; if (this._isUnsupportedGooglePayAPIVersion()) { throw new BraintreeError({ code: errors.GOOGLE_PAYMENT_UNSUPPORTED_VERSION.code, message: "The Braintree SDK does not support Google Pay version " + this._googlePayVersion + ". Please upgrade the version of your Braintree SDK and contact support if this error persists.", type: errors.GOOGLE_PAYMENT_UNSUPPORTED_VERSION.type, }); } } GooglePayment.prototype._waitForClient = function () { if (this._client) { return Promise.resolve(); } return this._createPromise.then( function (client) { this._client = client; }.bind(this) ); }; GooglePayment.prototype._isUnsupportedGooglePayAPIVersion = function () { // if we don't have createPaymentDatqRequest method for the specific // API version, then the version is not supported return !(this._googlePayVersion in CREATE_PAYMENT_DATA_REQUEST_METHODS); }; GooglePayment.prototype._getDefaultConfig = function () { if (!this._defaultConfig) { this._defaultConfig = generateGooglePayConfiguration( this._client.getConfiguration(), this._googlePayVersion, this._googleMerchantId ); } return this._defaultConfig; }; GooglePayment.prototype._createV1PaymentDataRequest = function ( paymentDataRequest ) { var defaultConfig = this._getDefaultConfig(); var overrideCardNetworks = paymentDataRequest.cardRequirements && paymentDataRequest.cardRequirements.allowedCardNetworks; var defaultConfigCardNetworks = defaultConfig.cardRequirements.allowedCardNetworks; var allowedCardNetworks = overrideCardNetworks || defaultConfigCardNetworks; paymentDataRequest = assign({}, defaultConfig, paymentDataRequest); // this way we can preserve allowedCardNetworks from default integration // if merchant did not pass any in `cardRequirements` paymentDataRequest.cardRequirements.allowedCardNetworks = allowedCardNetworks; return paymentDataRequest; }; GooglePayment.prototype._createV2PaymentDataRequest = function ( paymentDataRequest ) { var defaultConfig = this._getDefaultConfig(); if (paymentDataRequest.allowedPaymentMethods) { paymentDataRequest.allowedPaymentMethods.forEach(function (paymentMethod) { var defaultPaymentMethod = find( defaultConfig.allowedPaymentMethods, "type", paymentMethod.type ); if (defaultPaymentMethod) { applyDefaultsToPaymentMethodConfiguration( paymentMethod, defaultPaymentMethod ); } }); } paymentDataRequest = assign({}, defaultConfig, paymentDataRequest); return paymentDataRequest; }; /** * Create a configuration object for use in the `loadPaymentData` method. * * **Note**: Version 1 of the Google Pay Api is deprecated and will become unsupported in a future version. Until then, version 1 will continue to be used by default, and version 1 schema parameters and overrides will remain functional on existing integrations. However, new integrations and all following examples will be presented in the GooglePay version 2 schema. See [Google Pay's upgrade guide](https://developers.google.com/pay/api/web/guides/resources/update-to-latest-version) to see how to update your integration. * * If `options.googlePayVersion === 2` was set during the initial {@link module:braintree-web/google-payment.create|create} call, overrides must match the Google Pay v2 schema to be valid. * * @public * @param {object} overrides The supplied parameters for creating the PaymentDataRequest object. Required parameters are: * @param {object} overrides.transactionInfo Object according to the [Google Pay Transaction Info](https://developers.google.com/pay/api/web/reference/object#TransactionInfo) spec. * Optionally, any of the parameters in the [PaymentDataRequest](https://developers.google.com/pay/api/web/reference/object#PaymentDataRequest) parameters can be overridden, but note that it is recommended only to override top level parameters to avoid squashing deeply nested configuration objects. An example can be found below showing how to safely edit these deeply nested objects. * @example * var paymentDataRequest = googlePaymentInstance.createPaymentDataRequest({ * merchantInfo: { * merchantId: 'my-merchant-id-from-google' * }, * transactionInfo: { * currencyCode: 'USD', * totalPriceStatus: 'FINAL', * totalPrice: '100.00' * } * }); * * // Update card payment methods to require billing address * var cardPaymentMethod = paymentDataRequest.allowedPaymentMethods; * cardPaymentMethod.parameters.billingAddressRequired = true; * cardPaymentMethod.parameters.billingAddressParameters = { * format: 'FULL', * phoneNumberRequired: true * }; * * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }) * * paymentsClient.loadPaymentData(paymentDataRequest).then(function (response) { * // handle response with googlePaymentInstance.parseResponse * // (see below) * }); * @example <caption>With deferred client</caption> * googlePaymentInstance.createPaymentDataRequest({ * merchantInfo: { * merchantId: 'my-merchant-id-from-google' * }, * transactionInfo: { * currencyCode: 'USD', * totalPriceStatus: 'FINAL', * totalPrice: '100.00' * } * }).then(function (paymentDataRequest) { * // Update card payment methods to require billing address * var cardPaymentMethod = paymentDataRequest.allowedPaymentMethods; * cardPaymentMethod.parameters.billingAddressRequired = true; * cardPaymentMethod.parameters.billingAddressParameters = { * format: 'FULL', * phoneNumberRequired: true * }; * * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }) * * return paymentsClient.loadPaymentData(paymentDataRequest); * }).then(function (response) { * // handle response with googlePaymentInstance.parseResponse * // (see below) * }); * @returns {object|Promise} Returns a configuration object for Google PaymentDataRequest. If instantiated with `useDeferredClient` and an `authorization` it will return a promise that resolves with the configuration. */ GooglePayment.prototype.createPaymentDataRequest = function (overrides) { if (!this._useDeferredClient) { return this._createPaymentDataRequestSyncronously(overrides); } return this._waitForClient().then( function () { return this._createPaymentDataRequestSyncronously(overrides); }.bind(this) ); }; GooglePayment.prototype._createPaymentDataRequestSyncronously = function ( overrides ) { var paymentDataRequest = assign({}, overrides); var version = this._googlePayVersion; var createPaymentDataRequestMethod = CREATE_PAYMENT_DATA_REQUEST_METHODS[version]; analytics.sendEvent( this._createPromise, "google-payment.v" + version + ".createPaymentDataRequest" ); return this[createPaymentDataRequestMethod](paymentDataRequest); }; /** * Parse the response from the tokenization. * @public * @param {object} response The response back from the Google Pay tokenization. * @param {callback} [callback] The second argument, <code>data</code>, is a {@link GooglePay~tokenizePayload|tokenizePayload}. If no callback is provided, `parseResponse` returns a promise that resolves with a {@link GooglePayment~tokenizePayload|tokenizePayload}. * @example with callback * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }) * * paymentsClient.loadPaymentData(paymentDataRequestFromCreatePaymentDataRequest).then(function (response) { * googlePaymentInstance.parseResponse(response, function (err, data) { * if (err) { * // handle errors * } * // send parsedResponse.nonce to your server * }); * }); * @example with promise * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }) * * paymentsClient.loadPaymentData(paymentDataRequestFromCreatePaymentDataRequest).then(function (response) { * return googlePaymentInstance.parseResponse(response); * }).then(function (parsedResponse) { * // send parsedResponse.nonce to your server * }).catch(function (err) { * // handle errors * }); * @returns {(Promise|void)} Returns a promise that resolves the parsed response if no callback is provided. */ GooglePayment.prototype.parseResponse = function (response) { var self = this; return Promise.resolve() .then(function () { var payload; var rawResponse = response.apiVersion === 2 ? response.paymentMethodData.tokenizationData.token : response.paymentMethodToken.token; var parsedResponse = JSON.parse(rawResponse); var error = parsedResponse.error; if (error) { return Promise.reject(error); } analytics.sendEvent( self._createPromise, "google-payment.parseResponse.succeeded" ); if (parsedResponse.paypalAccounts) { payload = parsedResponse.paypalAccounts[0]; analytics.sendEvent( self._createPromise, "google-payment.parseResponse.succeeded.paypal" ); return Promise.resolve({ nonce: payload.nonce, type: payload.type, description: payload.description, }); } payload = parsedResponse.androidPayCards[0]; analytics.sendEvent( self._createPromise, "google-payment.parseResponse.succeeded.google-payment" ); return Promise.resolve({ nonce: payload.nonce, type: payload.type, description: payload.description, details: { cardType: payload.details.cardType, lastFour: payload.details.lastFour, lastTwo: payload.details.lastTwo, isNetworkTokenized: payload.details.isNetworkTokenized, bin: payload.details.bin, }, binData: payload.binData, }); }) .catch(function (error) { analytics.sendEvent( self._createPromise, "google-payment.parseResponse.failed" ); return Promise.reject( new BraintreeError({ code: errors.GOOGLE_PAYMENT_GATEWAY_ERROR.code, message: errors.GOOGLE_PAYMENT_GATEWAY_ERROR.message, type: errors.GOOGLE_PAYMENT_GATEWAY_ERROR.type, details: { originalError: error, }, }) ); }); }; /** * Cleanly tear down anything set up by {@link module:braintree-web/google-payment.create|create}. * @public * @param {callback} [callback] Called once teardown is complete. No data is returned if teardown completes successfully. * @example * googlePaymentInstance.teardown(); * @example <caption>With callback</caption> * googlePaymentInstance.teardown(function () { * // teardown is complete * }); * @returns {(Promise|void)} Returns a promise if no callback is provided. */ GooglePayment.prototype.teardown = function () { convertMethodsToError(this, methods(GooglePayment.prototype)); return Promise.resolve(); }; function applyDefaultsToPaymentMethodConfiguration( merchantSubmittedPaymentMethod, defaultPaymentMethod ) { Object.keys(defaultPaymentMethod).forEach(function (parameter) { if (typeof defaultPaymentMethod[parameter] === "object") { merchantSubmittedPaymentMethod[parameter] = assign( {}, defaultPaymentMethod[parameter], merchantSubmittedPaymentMethod[parameter] ); } else { merchantSubmittedPaymentMethod[parameter] = merchantSubmittedPaymentMethod[parameter] || defaultPaymentMethod[parameter]; } }); } module.exports = wrapPromise.wrapPrototype(GooglePayment); },{"../lib/analytics":14,"../lib/assign":16,"../lib/braintree-error":18,"../lib/convert-methods-to-error":20,"../lib/find":26,"../lib/generate-google-pay-configuration":27,"../lib/methods":29,"../lib/promise":30,"./errors":10,"@braintree/wrap-promise":8}],12:[function(_dereq_,module,exports){ "use strict"; /** * @module braintree-web/google-payment * @description A component to integrate with Google Pay. The majority of the integration uses [Google's pay.js JavaScript file](https://pay.google.com/gp/p/js/pay.js). The Braintree component generates the configuration object necessary for Google Pay to initiate the Payment Request and parse the returned data to retrieve the payment method nonce which is used to process the transaction on the server. */ var GooglePayment = _dereq_("./google-payment"); var BraintreeError = _dereq_("../lib/braintree-error"); var Promise = _dereq_("../lib/promise"); var createAssetsUrl = _dereq_("../lib/create-assets-url"); var createDeferredClient = _dereq_("../lib/create-deferred-client"); var basicComponentVerification = _dereq_("../lib/basic-component-verification"); var wrapPromise = _dereq_("@braintree/wrap-promise"); var VERSION = "3.87.0"; var errors = _dereq_("./errors"); /** * @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 Google Payment instance to be available right away by fetching the client configuration in the background. When this option is used, {@link GooglePayment#createPaymentDataRequest} will return a promise that resolves with the configuration instead of returning synchronously. * @param {number} [options.googlePayVersion] The version of the Google Pay API to use. Value of 2 is required to accept parameters documented [by Google](https://developers.google.com/pay/api/web/reference/object). Omit this parameter to use the deprecated Google Pay Version 1. * @param {string} [options.googleMerchantId] A Google merchant identifier issued after your website is approved by Google. Required when PaymentsClient is initialized with an environment property of PRODUCTION, but may be omitted in TEST environment. * @param {callback} [callback] The second argument, `data`, is the {@link GooglePayment} instance. If no callback is provided, `create` returns a promise that resolves with the {@link GooglePayment} instance. * @example <caption>Simple Example</caption> * // include https://pay.google.com/gp/p/js/pay.js in a script tag * // on your page to load the `google.payments.api.PaymentsClient` global object. * * var paymentButton = document.querySelector('#google-pay-button'); * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }); * * braintree.client.create({ * authorization: 'tokenization-key-or-client-token' * }).then(function (clientInstance) { * return braintree.googlePayment.create({ * client: clientInstance, * googlePayVersion: 2, * googleMerchantId: 'your-merchant-id-from-google' * }); * }).then(function (googlePaymentInstance) { * paymentButton.addEventListener('click', function (event) { * var paymentDataRequest; * * event.preventDefault(); * * paymentDataRequest = googlePaymentInstance.createPaymentDataRequest({ * transactionInfo: { * currencyCode: 'USD', * totalPriceStatus: 'FINAL', * totalPrice: '100.00' * } * }); * * paymentsClient.loadPaymentData(paymentDataRequest).then(function (paymentData) { * return googlePaymentInstance.parseResponse(paymentData); * }).then(function (result) { * // send result.nonce to your server * }).catch(function (err) { * // handle err * }); * }); * }); * @example <caption>Check Browser and Customer Compatibility</caption> * var paymentsClient = new google.payments.api.PaymentsClient({ * environment: 'TEST' // or 'PRODUCTION' * }); * * function setupGooglePayButton(googlePaymentInstance) { * var button = document.createElement('button'); * * button.id = 'google-pay'; * button.appendChild(document.createTextNode('Google Pay')); * button.addEventListener('click', function (event) { * var paymentRequestData; * * event.preventDefault(); * * paymentDataRequest = googlePaymentInstance.createPaymentDataRequest({ * transactionInfo: { * currencyCode: 'USD', * totalPriceStatus: 'FINAL', * totalPrice: '100.00' // your amount * } * }); * * paymentsClient.loadPaymentData(paymentDataRequest).then(function (paymentData) { * return googlePaymentInstance.parseResponse(paymentData); * }).then(function (result) { * // send result.nonce to your server * }).catch(function (err) { * // handle errors * }); * }); * * document.getElementById('container').appendChild(button); * } * * braintree.client.create({ * authorization: 'tokenization-key-or-client-token' * }).then(function (clientInstance) { * return braintree.googlePayment.create({ * client: clientInstance, * googlePayVersion: 2, * googleMerchantId: 'your-merchant-id-from-google' * }); * }).then(function (googlePaymentInstance) { * * return paymentsClient.isReadyToPay({ * // see https://developers.google.com/pay/api/web/reference/object#IsReadyToPayRequest for all options * apiVersion: 2, * apiVersionMinor: 0, * allowedPaymentMethods: googlePaymentInstance.createPaymentDataRequest().allowedPaymentMethods, * existingPaymentMethodRequired: true * }); * }).then(function (response) { * if (response.result) { * setupGooglePayButton(googlePaymentInstance); * } * }).catch(function (err) { * // handle setup errors * }); * * @returns {(Promise|void)} Returns a promise if no callback is provided. */ function create(options) { var name = "Google Pay"; return basicComponentVerification .verify({ name: name, client: options.client, authorization: options.authorization, }) .then(function () { var createPromise, instance; createPromise = createDeferredClient .create({ authorization: options.authorization, client: options.client, debug: options.debug, assetsUrl: createAssetsUrl.create(options.authorization), name: name, }) .then(function (client) { var configuration = client.getConfiguration(); options.client = client; if (!configuration.gatewayConfiguration.androidPay) { return Promise.reject( new BraintreeError(errors.GOOGLE_PAYMENT_NOT_ENABLED) ); } return client; }); options.createPromise = createPromise; instance = new GooglePayment(options); if (!options.useDeferredClient) { return createPromise.then(function (client) { instance._client = client; return instance; }); } return instance; }); } module.exports = { create: wrapPromise(create), /** * @description The current version of the SDK, i.e. `{@pkg version}`. * @type {string} */ VERSION: VERSION, }; },{"../lib/basic-component-verification":17,"../lib/braintree-error":18,"../lib/create-assets-url":21,"../lib/create-deferred-client":23,"../lib/promise":30,"./errors":10,"./google-payment":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":19,"./create-authorization-data":22,"./json-clone":28}],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":19,"./promise":30}],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 assignNormalized = typeof Object.assign === "function" ? Object.assign : assignPolyfill; function assignPolyfill(destination) { var i, source, key; for (i = 1; i < arguments.length; i++) { source = arguments[i]; for (key in source) { if (source.hasOwnProperty(key)) { destination[key] = source[key]; } } } return destination; } module.exports = { assign: assignNormalized, _assign: assignPolyfill, }; },{}],17:[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":18,"./errors":25,"./promise":30}],18:[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 Braintr