braintree-web
Version:
A suite of tools for integrating Braintree in the browser
1,215 lines (1,126 loc) • 71.6 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 = {})).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 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.type) {
script.setAttribute("type", "".concat(options.type));
}
if (options.crossorigin) {
script.setAttribute("crossorigin", "".concat(options.crossorigin));
}
Object.keys(attrs).forEach(function (key) {
script.setAttribute("data-".concat(key), "".concat(attrs[key]));
});
scriptLoadPromise = new Promise(function (resolve, reject) {
script.addEventListener("load", function () {
resolve(script);
});
script.addEventListener("error", function () {
reject(new Error("".concat(options.src, " failed to load.")));
});
script.addEventListener("abort", function () {
reject(new Error("".concat(options.src, " has aborted.")));
});
container.appendChild(script);
});
scriptPromiseCache[stringifiedOptions] = scriptLoadPromise;
return scriptLoadPromise;
}
loadScript.clearCache = function () {
scriptPromiseCache = {};
};
module.exports = loadScript;
},{}],2:[function(_dereq_,module,exports){
module.exports = _dereq_("./dist/load-script");
},{"./dist/load-script":1}],3:[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;
},{}],4:[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;
},{}],5:[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;
},{}],6:[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":3,"./lib/once":4,"./lib/promise-or-callback":5}],7:[function(_dereq_,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.loadAxo = {}));
})(this, (function (exports) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
var dist = {};
var scriptPromiseCache = {};
function loadScript$1(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.type) {
script.setAttribute("type", "".concat(options.type));
}
if (options.crossorigin) {
script.setAttribute("crossorigin", "".concat(options.crossorigin));
}
Object.keys(attrs).forEach(function (key) {
script.setAttribute("data-".concat(key), "".concat(attrs[key]));
});
scriptLoadPromise = new Promise(function (resolve, reject) {
script.addEventListener("load", function () {
resolve(script);
});
script.addEventListener("error", function () {
reject(new Error("".concat(options.src, " failed to load.")));
});
script.addEventListener("abort", function () {
reject(new Error("".concat(options.src, " has aborted.")));
});
container.appendChild(script);
});
scriptPromiseCache[stringifiedOptions] = scriptLoadPromise;
return scriptLoadPromise;
}
loadScript$1.clearCache = function () {
scriptPromiseCache = {};
};
var loadScript_1$1 = loadScript$1;
var loadStylesheet$1 = function loadStylesheet(options) {
var stylesheet = document.querySelector("link[href=\"".concat(options.href, "\"]"));
if (stylesheet) {
return Promise.resolve(stylesheet);
}
stylesheet = document.createElement("link");
var container = options.container || document.head;
stylesheet.setAttribute("rel", "stylesheet");
stylesheet.setAttribute("type", "text/css");
stylesheet.setAttribute("href", options.href);
stylesheet.setAttribute("id", options.id);
if (container.firstChild) {
container.insertBefore(stylesheet, container.firstChild);
}
else {
container.appendChild(stylesheet);
}
return Promise.resolve(stylesheet);
};
Object.defineProperty(dist, "__esModule", { value: true });
dist.loadStylesheet = loadScript_1 = dist.loadScript = void 0;
var loadScript = loadScript_1$1;
var loadScript_1 = dist.loadScript = loadScript;
var loadStylesheet = loadStylesheet$1;
dist.loadStylesheet = loadStylesheet;
var CDNX_PROD = "https://www.paypalobjects.com";
var ASSET_NAME = {
minified: "axo.min",
unminified: "axo",
};
var FL_NAMESPACE = "fastlane";
var ASSET_PATH = "connect-boba";
var LOCALE_PATH = "".concat(ASSET_PATH, "/locales/");
var constants = {
AXO_ASSET_NAME: ASSET_NAME,
AXO_ASSET_PATH: ASSET_PATH,
LOCALE_PATH: LOCALE_PATH,
CDNX_PROD: CDNX_PROD,
};
var AxoSupportedPlatforms = {
BT: "BT",
PPCP: "PPCP",
};
/**
* Checks if the current environment is an AMD environment.
*
* @returns {boolean} True if the environment is AMD, false otherwise.
*/
function isAmdEnv() {
return typeof window.define === "function" && !!window.define.amd;
}
/**
* Checks if the current environment is a RequireJS environment.
*
* @returns {boolean} True if the environment is RequireJS, false otherwise.
*/
function isRequireJsEnv() {
return (isAmdEnv() &&
typeof window.requirejs === "function" &&
typeof window.requirejs.config === "function");
}
/**
* Safely loads BT modules by checking if the module already exists and verifying if versions mismatch
*
* @param loadConfig <BtModuleLoadConfig> Configuration of BT Module to load
* @param version <string> version that should be passed from the client getVersion
* @returns Promise<HTMLScriptElement>
* @returns Promise<true> when BT module with same version already exists
* @returns Promise.reject(err) when BT module already exists but versions mismatch or empty version passed in
*/
function safeLoadBtModule(loadConfig, version, minified) {
var _a, _b;
if (minified === void 0) { minified = true; }
return __awaiter(this, void 0, void 0, function () {
var bt, existingVersion;
return __generator(this, function (_c) {
bt = getBraintree();
if (bt && bt[loadConfig.module]) {
if (version && ((_a = bt[loadConfig.module]) === null || _a === void 0 ? void 0 : _a.VERSION) !== version) {
existingVersion = (_b = bt[loadConfig.module]) === null || _b === void 0 ? void 0 : _b.VERSION;
throw new Error("".concat(loadConfig.module, " already loaded with version ").concat(existingVersion, " cannot load version ").concat(version));
}
else {
return [2 /*return*/, true];
}
}
if (!version) {
throw new Error("Attempted to load ".concat(loadConfig.module, " without specifying version"));
}
return [2 /*return*/, loadBtModule(loadConfig, version, minified)];
});
});
}
/**
* Reads the version and to load the correct version of Bt module
*
* @param loadConfig <BtModuleLoadConfig> Configuration of BT Module to load
* @param version <string> Bt module version
* @returns Promise<HTMLScriptElement> or
*/
function loadBtModule(loadConfig, version, minified) {
if (minified === void 0) { minified = true; }
if (isAmdEnv()) {
var module_1 = minified
? loadConfig.amdModule.minified
: loadConfig.amdModule.unminified;
return new Promise(function (resolve, reject) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.require([module_1], resolve, reject);
});
}
var script = minified
? loadConfig.script.minified
: loadConfig.script.unminified;
return loadScript_1({
id: "".concat(loadConfig.id, "-").concat(version),
src: "https://js.braintreegateway.com/web/".concat(version, "/js/").concat(script),
});
}
/**
* Looks for the Braintree web sdk on the window object
*
* @returns Braintree web sdk
*/
function getBraintree() {
return window === null || window === void 0 ? void 0 : window.braintree;
}
var _a, _b;
/**
* Maps to the BT module namespace created on the window.braintree object
*/
var BtModule = {
Client: "client",
HostedCardFields: "hostedFields",
};
var BT_NAMESPACE = "braintree";
var BT_ASSET_NAME = (_a = {},
_a[BtModule.Client] = "client",
_a[BtModule.HostedCardFields] = "hosted-fields",
_a);
var btModulesLoadConfig = (_b = {},
_b[BtModule.Client] = {
id: "client",
module: BtModule.Client,
amdModule: {
unminified: "".concat(BT_NAMESPACE, "/").concat(BT_ASSET_NAME[BtModule.Client]),
minified: "".concat(BT_NAMESPACE, "/").concat(BT_ASSET_NAME[BtModule.Client], ".min"),
},
script: {
unminified: "".concat(BT_ASSET_NAME[BtModule.Client], ".js"),
minified: "".concat(BT_ASSET_NAME[BtModule.Client], ".min.js"),
},
},
_b[BtModule.HostedCardFields] = {
id: "hcf",
module: BtModule.HostedCardFields,
amdModule: {
unminified: "".concat(BT_NAMESPACE, "/").concat(BT_ASSET_NAME[BtModule.HostedCardFields]),
minified: "".concat(BT_NAMESPACE, "/").concat(BT_ASSET_NAME[BtModule.HostedCardFields], ".min"),
},
script: {
unminified: "".concat(BT_ASSET_NAME[BtModule.HostedCardFields], ".js"),
minified: "".concat(BT_ASSET_NAME[BtModule.HostedCardFields], ".min.js"),
},
},
_b);
/**
* Loads accelerated checkout components.
* @param options object with a minified parameter to determine if the script that is loaded should be minified or not (defaults to true if)
* @returns an object with metadata with a localeUrl parameter to be read by AXO SDK
*/
function loadAxo(options) {
return __awaiter(this, void 0, void 0, function () {
var btSdkVersion, minified, assetUrl, localeUrl;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
performance.mark("pp_axo_sdk_init_invoked");
btSdkVersion = options.btSdkVersion, minified = options.minified;
assetUrl = getAssetsUrl(options);
localeUrl = getLocaleUrl(options);
if (!(options.platform === AxoSupportedPlatforms.BT)) return [3 /*break*/, 2];
return [4 /*yield*/, Promise.all([
safeLoadBtModule(btModulesLoadConfig.hostedFields, btSdkVersion, minified),
loadAXOScript(assetUrl, minified),
])];
case 1:
_a.sent();
return [3 /*break*/, 5];
case 2:
if (!(options.platform === AxoSupportedPlatforms.PPCP)) return [3 /*break*/, 4];
return [4 /*yield*/, Promise.all([
safeLoadBtModule(btModulesLoadConfig.client, btSdkVersion, minified),
safeLoadBtModule(btModulesLoadConfig.hostedFields, btSdkVersion, minified),
loadAXOScript(assetUrl, minified),
])];
case 3:
_a.sent();
return [3 /*break*/, 5];
case 4: throw new Error("unsupported axo platform");
case 5: return [2 /*return*/, { metadata: { localeUrl: localeUrl } }];
}
});
});
}
/**
* Reads the url and to load the axo bundle script
* @param url (Required) string url for the correct axo asset
* @returns Promise<HTMLScriptElement>
*/
function loadAXOScript(url, minified) {
var _a;
if (minified === void 0) { minified = true; }
if (isAmdEnv()) {
// AMD environment
if (isRequireJsEnv()) {
// Let's configure RequireJS
requirejs.config({
paths: (_a = {},
_a[FL_NAMESPACE] = url,
_a),
});
}
var moduleName_1 = "".concat(FL_NAMESPACE, "/").concat(minified
? constants.AXO_ASSET_NAME.minified
: constants.AXO_ASSET_NAME.unminified);
return new Promise(function (resolve, reject) {
window.require([moduleName_1], resolve, reject);
});
}
// Not an AMD environment
return loadScript_1({
id: "axo-id",
src: url,
forceScriptReload: true,
});
}
/**
* Prepends the domain to the asset url
* @param options object with assetUrl and bundleid parameters to determine which URL to return
* @returns full domain and assets URL as string
*/
function generateAssetUrl(_a) {
var assetUrl = _a.assetUrl, bundleId = _a.bundleId;
return bundleId
? "https://cdn-".concat(bundleId, ".static.engineering.dev.paypalinc.com/").concat(assetUrl)
: "".concat(constants.CDNX_PROD, "/").concat(assetUrl);
}
/**
* Retrieves either the minified or unminified assets URL as specified
* @param options (Optional) object with a minified and metadata with bundleIdOverride parameters to determine which URL to return
* @returns assets URL as string
*/
function getAssetsUrl(options) {
var _a;
var assetName = (options === null || options === void 0 ? void 0 : options.minified) !== false
? constants.AXO_ASSET_NAME.minified
: constants.AXO_ASSET_NAME.unminified;
var assetUrl = isAmdEnv()
? constants.AXO_ASSET_PATH
: "".concat(constants.AXO_ASSET_PATH, "/").concat(assetName, ".js");
return generateAssetUrl({
assetUrl: assetUrl,
bundleId: (_a = options === null || options === void 0 ? void 0 : options.metadata) === null || _a === void 0 ? void 0 : _a.bundleIdOverride,
});
}
/**
* Retrieves the Locales URL, the path to our language files
* @param options (Optional) object with a minified and metadata with bundleIdOverride parameters to determine which URL to return
* @returns locale URL as string
*/
function getLocaleUrl(options) {
var _a;
return generateAssetUrl({
assetUrl: constants.LOCALE_PATH,
bundleId: (_a = options === null || options === void 0 ? void 0 : options.metadata) === null || _a === void 0 ? void 0 : _a.bundleIdOverride,
});
}
exports.constants = constants;
exports.loadAxo = loadAxo;
}));
},{}],8:[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":16}],9:[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 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];
if (
paymentDataRequest.transactionInfo &&
paymentDataRequest.transactionInfo.totalPrice
) {
paymentDataRequest.transactionInfo.totalPrice =
paymentDataRequest.transactionInfo.totalPrice.toString();
}
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":12,"../lib/assign":14,"../lib/braintree-error":16,"../lib/convert-methods-to-error":18,"../lib/find":24,"../lib/generate-google-pay-configuration":25,"../lib/methods":27,"./errors":8,"@braintree/wrap-promise":6}],10:[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 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.118.2";
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":15,"../lib/braintree-error":16,"../lib/create-assets-url":19,"../lib/create-deferred-client":21,"./errors":8,"./google-payment":9,"@braintree/wrap-promise":6}],11:[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;
}
function addEventMetadata(clientInstanceOrPromise) {
var configuration = clientInstanceOrPromise.getConfiguration();
var authAttrs = createAuthorizationData(configuration.authorization).attrs;
var isProd = configuration.gatewayConfiguration.environment === "production";
/* eslint-disable camelcase */
var metadata = {
api_integration_type: configuration.analyticsMetadata.integrationType,
app_id: window.location.host,
c_sdk_ver: constants.VERSION,
component: "braintreeclientsdk",
merchant_sdk_env: isProd ? "production" : "sandbox",
merchant_id: configuration.gatewayConfiguration.