Home Reference Source

src/script.js

/* @flow */

import { getCurrentScriptUID, ATTRIBUTES, parseQuery, getBrowserLocales, base64decode,
    values, getCurrentScript, memoize, stringifyError, getScript } from '@krakenjs/belter/src';
import { COUNTRY, SDK_SETTINGS, SDK_QUERY_KEYS, INTENT, COMMIT, VAULT, CURRENCY,
    FUNDING, CARD, COUNTRY_LANGS, DEFAULT_INTENT, DEFAULT_CURRENCY, DEFAULT_VAULT,
    QUERY_BOOL, LANG, type LocaleType, DEFAULT_SALE_COMMIT, DEFAULT_NONSALE_COMMIT,
    PAGE_TYPES } from '@paypal/sdk-constants/src';

import { getPath, getDefaultNamespace, getSDKHost } from './global';
import { CLIENT_ID_ALIAS } from './config';
import { getComputedLocales } from './utils';

type GetSDKScript = () => HTMLScriptElement;

export const getSDKScript : GetSDKScript = memoize(() => {
    if (__TEST__) {
        const script = getScript({ host: getSDKHost(), path: getPath(), reverse: true });
        if (!script) {
            throw new Error(`Can not find SDK test script`);
        }
        return script;
    }

    try {
        return getCurrentScript();
    } catch (err) {
        throw new Error(`PayPal Payments SDK script not found on page! Expected to find <script src="https://${ getSDKHost() }${  getPath() }">\n\n${ stringifyError(err) }`);
    }
});

type GetSDKAttributes = () => { [string] : string };

export const getSDKAttributes : GetSDKAttributes = memoize(() => {
    const sdkScript = getSDKScript();
    const result = {};
    for (const attr of sdkScript.attributes) {
        if (attr.name.indexOf('data-') === 0) {
            result[attr.name] = attr.value;
        }
    }
    result[ATTRIBUTES.UID] = getCurrentScriptUID();
    return result;
});

export function getSDKAttribute<T : string | void>(name : $Values<typeof SDK_SETTINGS>, def : T) : T {
    // $FlowFixMe
    return getSDKAttributes()[name] || def;
}

export function getSDKQueryParams() : { [string] : string } {
    const script = getSDKScript();
    return parseQuery(script.src.split('?')[1] || '');
}

type GetSDKQueryParam =
    // eslint-disable-next-line no-undef
    (<T : string>($Values<typeof SDK_QUERY_KEYS>) => T | void) &
    // eslint-disable-next-line no-undef
    (<T : string>($Values<typeof SDK_QUERY_KEYS>, T) => T);

export const getSDKQueryParam : GetSDKQueryParam = <T>(name : string, def : T) => {
    // $FlowFixMe
    return getSDKQueryParams()[name] || def;
};

export function getScriptUrl() : string {
    const src = getSDKScript().getAttribute('src');
    if (!src) {
        throw new Error(`Can not find src for sdk script`);
    }
    return src;
}

export function getSDKQueryParamBool<T : boolean>(name : $Values<typeof SDK_QUERY_KEYS>, def? : T) : T {
    // $FlowFixMe
    return getSDKQueryParam(name, def ? def.toString() : QUERY_BOOL.FALSE) === QUERY_BOOL.TRUE;
}

export function getClientID() : string {
    const clientID = getSDKQueryParam(SDK_QUERY_KEYS.CLIENT_ID);

    if (!clientID) {
        throw new Error(`Expected ${ SDK_QUERY_KEYS.CLIENT_ID } parameter in sdk url`);
    }

    if (CLIENT_ID_ALIAS[clientID]) {
        return CLIENT_ID_ALIAS[clientID];
    }

    return clientID;
}

export function getMerchantID() : $ReadOnlyArray<string> {
    const merchantIDString = getSDKQueryParam(SDK_QUERY_KEYS.MERCHANT_ID);

    if (merchantIDString === '*') {
        // get multiple merchant ids or emails from data-merchant-id
        const merchantIDAttribute = getSDKAttribute(SDK_SETTINGS.MERCHANT_ID);

        if (!merchantIDAttribute) {
            throw new Error(`Must pass ${ SDK_SETTINGS.MERCHANT_ID } when ${ SDK_QUERY_KEYS.MERCHANT_ID }=* passed in url`);
        }

        const merchantID = merchantIDAttribute.split(',');

        if (merchantID.length <= 1) {
            throw new Error(`Must pass multiple merchant ids to ${ SDK_SETTINGS.MERCHANT_ID }. If passing a single id, pass ${ SDK_QUERY_KEYS.MERCHANT_ID }=XYZ in url`);
        }

        // check duplicates
        const hasDuplicate = merchantID.some((val, i) => merchantID && merchantID.indexOf(val) !== i);

        if (hasDuplicate) {
            throw new Error(`Duplicates ${ SDK_SETTINGS.MERCHANT_ID }. Must pass unique merchant ids to ${ SDK_SETTINGS.MERCHANT_ID }.`);
        }
        return merchantID;
    }

    if (merchantIDString) {
        return merchantIDString.split(',');
    }

    return [];
}

export function getIntent() : $Values<typeof INTENT> {
    return getSDKQueryParam(SDK_QUERY_KEYS.INTENT, DEFAULT_INTENT);
}

export function getCommit() : $Values<typeof COMMIT> {
    return getSDKQueryParamBool(SDK_QUERY_KEYS.COMMIT, getIntent() === INTENT.CAPTURE ? DEFAULT_SALE_COMMIT : DEFAULT_NONSALE_COMMIT);
}

export function getVault() : $Values<typeof VAULT> {
    return getSDKQueryParamBool(SDK_QUERY_KEYS.VAULT, DEFAULT_VAULT);
}

export function getCurrency() : $Values<typeof CURRENCY> {
    return getSDKQueryParam(SDK_QUERY_KEYS.CURRENCY, DEFAULT_CURRENCY);
}

export function getEnableFunding() : $ReadOnlyArray<?$Values<typeof FUNDING>> {
    const funding = getSDKQueryParam(SDK_QUERY_KEYS.ENABLE_FUNDING);
    if (funding) {
        return funding.split(',');
    }
    return [];
}

export function getDisableFunding() : $ReadOnlyArray<?$Values<typeof FUNDING>> {
    const funding = getSDKQueryParam(SDK_QUERY_KEYS.DISABLE_FUNDING);
    if (funding) {
        return funding.split(',');
    }
    return [];
}

export function getDisableCard() : $ReadOnlyArray<?$Values<typeof CARD>> {
    const funding = getSDKQueryParam(SDK_QUERY_KEYS.DISABLE_CARD);
    if (funding) {
        return funding.split(',');
    }
    return [];
}

export function getBuyerCountry() : ?$Values<typeof COUNTRY> {
    return getSDKQueryParam(SDK_QUERY_KEYS.BUYER_COUNTRY);
}

export function getNamespace() : string {
    return getSDKAttribute(SDK_SETTINGS.NAMESPACE) || getDefaultNamespace();
}

export function getClientToken() : ?string {
    return getSDKAttribute(SDK_SETTINGS.CLIENT_TOKEN);
}

export function getAmount() : ?string {
    const amount = getSDKAttribute(SDK_SETTINGS.AMOUNT);
    if (amount && !amount.match(/^\d+\.\d\d$/)) {
        throw new Error(`Invalid amount: ${ amount }`);
    }
    return amount;
}

export function getUserIDToken() : ?string {
    return getSDKAttribute(SDK_SETTINGS.USER_ID_TOKEN);
}

export function getClientAccessToken() : ?string {
    const clientToken = getClientToken();

    if (clientToken) {
        return JSON.parse(base64decode(clientToken)).paypal.accessToken;
    }
}

export function getPartnerAttributionID() : ?string {
    return getSDKAttribute(SDK_SETTINGS.PARTNER_ATTRIBUTION_ID);
}

export function getMerchantRequestedPopupsDisabled() : boolean {
    return getSDKAttribute(SDK_SETTINGS.POPUPS_DISABLED) === 'true';
}

export function getPageType() : ?string {
    const pageType = getSDKAttribute(SDK_SETTINGS.PAGE_TYPE, '');
    const validPageType = values(PAGE_TYPES).indexOf(pageType.toLowerCase()) !== -1;

    if (!validPageType && pageType.length) {
        throw new Error(`Invalid page type, '${ pageType }'`);
    }
    return pageType.toLowerCase();
}


export function getLocale() : LocaleType {
    const locale = getSDKQueryParam(SDK_QUERY_KEYS.LOCALE);

    if (locale) {
        return getComputedLocales(locale);
    }

    for (let { country, lang } of getBrowserLocales()) {
        country = country && COUNTRY[country];
        lang = lang && LANG[lang.toUpperCase()];

        if (country && lang && COUNTRY_LANGS[country] && COUNTRY_LANGS[country].indexOf(lang) !== -1) {
            return { country, lang };
        } else if (lang) {
            // We infer country from language if there is only one possible country match
            const possibleCountries = Object.keys(COUNTRY_LANGS).filter(c => COUNTRY_LANGS[c].some(l => l === lang));
            
            if (possibleCountries.length === 1) {
                const possibleCountry = possibleCountries[0];
                return { country: possibleCountry, lang };
            }
        }
    }

    for (const { country } of getBrowserLocales()) {
        if (COUNTRY_LANGS.hasOwnProperty(country)) {
            // $FlowFixMe
            return { country, lang: COUNTRY_LANGS[country][0] };
        }
    }

    return {
        lang:    LANG.EN,
        country: COUNTRY.US
    };
}

export function getCSPNonce() : string {
    return getSDKAttribute(SDK_SETTINGS.CSP_NONCE) || '';
}

export function getEnableThreeDomainSecure() : boolean {
    return getSDKAttributes().hasOwnProperty(SDK_SETTINGS.ENABLE_3DS);
}

export function getSDKIntegrationSource() : ?string {
    return getSDKAttribute(SDK_SETTINGS.SDK_INTEGRATION_SOURCE);
}

export function getUserExperienceFlow() : ?string {
    return getSDKAttribute(SDK_SETTINGS.USER_EXPERIENCE_FLOW);
}

// whether in zoid window
export function isChildWindow() : boolean {
    return Boolean(window.xprops);
}

export function getUserAccessToken() : ?string {
    // pass
}

export function getUserAuthCode() : ?string {
    // pass
}

// Remove
export function getCountry() : $Values<typeof COUNTRY> {
    return getLocale().country;
}

// Remove
export function getLang() : $Values<typeof LANG> {
    return getLocale().lang;
}