UNPKG

@comgate/checkout-js-dev

Version:

Loading wrapper for Comgate Checkout library.

704 lines (703 loc) 24.5 kB
/* * @comgate/checkout-js-dev v2.0.4 (https://www.npmjs.com/package/@comgate/checkout-js-dev) * Copyright 2025 - Comgate a.s. * Licensed under EULA (https://www.unpkg.com/@comgate/checkout-js-dev@2.0.4/LICENSE) */ const VERSION_DEV = "dev"; const VERSION_1 = "1"; const VERSION_2 = "2"; const ENVIRONMENT_DEV = "dev"; const ENVIRONMENT_TEST = "test"; const ENVIRONMENT_PROD = "prod"; const ENVIRONMENT_PREFERRED = ENVIRONMENT_PROD; const ENVIRONMENT_DEV_CDN_URL = "https://localhost:8787/sdk/"; const ENVIRONMENT_TEST_CDN_URL = "https://checkout.comgate-test.cz/sdk/"; const ENVIRONMENT_PROD_CDN_URL = "https://checkout.comgate.cz/sdk/"; const ENVIRONMENT_DEV_API_URL = "https://payments_web/"; const ENVIRONMENT_TEST_API_URL = "https://payments.comgate-test.cz/"; const ENVIRONMENT_PROD_API_URL = "https://payments.comgate.cz/"; const checkoutEnvironments = [ENVIRONMENT_DEV, ENVIRONMENT_TEST, ENVIRONMENT_PROD]; const VERSION_PREFERRED = VERSION_2; const checkoutVersions = [VERSION_1, VERSION_2, VERSION_DEV]; const checkoutIdRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; const versionRegex = new RegExp(`^([12]\.[0-9]+\.[0-9]+|${checkoutVersions.join("|")})$`, "i"); const semverRegex = new RegExp(`^([12]\.[0-9]+\.[0-9]+)$`, "i"); const MODULE_LOADER = "loader"; const MODULE_CORE = "core"; const FILE_MODULE_CORE = "checkout-core.min.js"; const moduleCore = { name: MODULE_CORE, events: { ready: "ComgateCheckoutCoreLoaded" }, mountPoint: ["comgate", "checkout", "core"], file: FILE_MODULE_CORE }; const MODULE_APPLEPAY = "applepay"; const FILE_MODULE_APPLEPAY = "checkout-apple-pay.min.js"; const moduleApplePay = { name: MODULE_APPLEPAY, events: { ready: "ComgateCheckoutApplePayLoaded" }, mountPoint: ["comgate", "checkout", "applepay"], file: FILE_MODULE_APPLEPAY }; const MODULE_GOOGLEPAY = "googlepay"; const FILE_MODULE_GOOGLEPAY = "checkout-google-pay.min.js"; const moduleGooglePay = { name: MODULE_GOOGLEPAY, events: { ready: "ComgateCheckoutGooglePayLoaded" }, mountPoint: ["comgate", "checkout", "googlepay"], file: FILE_MODULE_GOOGLEPAY }; const EVENT_MODULES_LOADED = "comgate-checkout-js-module-loaded"; const EVENT_MODULES_PREFETCHED = "comgate-checkout-js-module-prefetched"; const MODULE_LOAD_SUCCESSFULLY = "true"; const MODULE_LOAD_FAILED = "false"; const resolveFileUrl = (cdnBaseUrl, version2, file) => { return `${cdnBaseUrl + version2.version}${resolveFileName(version2, file)}`; }; const resolveFileName = (version2, file) => { if (file && file.length > 0) { return "/" + expandFileName(file, version2.hash); } return ""; }; const expandFileName = (file, hash) => { if (hash) { const lastDot = file.lastIndexOf("."); if (lastDot >= 0) { const name = file.slice(0, lastDot); const ext = file.slice(lastDot); return `${name}.${hash}${ext}`; } } return file; }; const createPrefetchLinkElement = (prefetchId, version2, baseUrl, file) => { const prefetch2 = document.createElement("link"); prefetch2.id = prefetchId; prefetch2.rel = "prefetch"; prefetch2.as = "script"; prefetch2.href = resolveFileUrl(baseUrl, version2, file); return prefetch2; }; const createScriptElement = (loadId, version2, isAsync = true, isDeferred = false, baseUrl, file) => { const script = document.createElement("script"); script.id = loadId; script.src = resolveFileUrl(baseUrl, version2, file); script.async = isAsync; script.defer = isDeferred; return script; }; const setElementData = (element, name, value) => { try { if (element && element instanceof HTMLElement && "dataset" in element) { element.dataset[name] = value; return true; } } catch (error) { } return false; }; const getElementData = (element, name) => { try { if (element && element instanceof HTMLElement && "dataset" in element) { return element.dataset[name]; } } catch (error) { } return void 0; }; const resolveDebug = (config) => { return config.debug === true; }; const resolveEnvironment = (config) => { return ("environment" in config ? config.environment : ENVIRONMENT_PREFERRED) || ENVIRONMENT_PREFERRED; }; const resolveUrl = (config, type) => { const env = resolveEnvironment(config); if (type === "cdn") { return { [ENVIRONMENT_DEV]: ENVIRONMENT_DEV_CDN_URL, [ENVIRONMENT_TEST]: ENVIRONMENT_TEST_CDN_URL, [ENVIRONMENT_PROD]: ENVIRONMENT_PROD_CDN_URL }[env]; } return { [ENVIRONMENT_DEV]: ENVIRONMENT_DEV_API_URL, [ENVIRONMENT_TEST]: ENVIRONMENT_TEST_API_URL, [ENVIRONMENT_PROD]: ENVIRONMENT_PROD_API_URL }[env]; }; let serverVersions; const semverPrefix = "v/"; const majorPrefix = "@"; const resolveVersion = async (config, cdnBaseUrl) => { try { if (!serverVersions) { await safeFetch(cdnBaseUrl + "versions.json").then((res) => { if (res.ok && res.isJson) { serverVersions = res.data; } else if (resolveDebug(config)) { console.warn("Checkout SDK: can't fetch versions.json, using cdn fallback.", { details: res == null ? void 0 : res.error }); } }).catch((error) => { if (resolveDebug(config)) { console.warn("Checkout SDK: can't fetch versions.json, using cdn fallback.", { details: error }); } }); } return getExpandedVersion(config.version, serverVersions); } catch (error) { return { version: majorPrefix + VERSION_PREFERRED }; } }; function getExpandedVersion(custom, server) { if (!server) { if (custom && semverRegex.test(custom)) { return { version: semverPrefix + custom }; } if (custom && checkoutVersions.includes(custom)) { return { version: majorPrefix + custom }; } return { version: majorPrefix + VERSION_PREFERRED }; } if (custom && semverRegex.test(custom)) { const major = custom.split(".")[0]; if (server.majors[major]) { return { hash: server.majors[major].hash, version: semverPrefix + custom }; } } if (custom && custom in server.majors) { return { hash: server.majors[custom].hash, version: semverPrefix + server.majors[custom].latest }; } if (VERSION_PREFERRED in server.majors) { return { hash: server.majors[VERSION_PREFERRED].hash, version: semverPrefix + server.majors[VERSION_PREFERRED].latest }; } return { version: majorPrefix + VERSION_PREFERRED }; } function validateNumber(value, min, max, defaultValue) { if (value && typeof value === "number") { if (value < min) { return min; } if (value > max) { return max; } return value; } return defaultValue; } const TIMEOUT_IS_MOUNTED_DEFAULT$1 = 1e4; const TIMEOUT_IS_MOUNTED_MIN$1 = 500; const TIMEOUT_IS_MOUNTED_MAX$1 = 3e4; async function safeFetch(url, options = {}, timeout = 3e3) { const timeoutMs = validateNumber(timeout, TIMEOUT_IS_MOUNTED_MIN$1, TIMEOUT_IS_MOUNTED_MAX$1, TIMEOUT_IS_MOUNTED_DEFAULT$1); let controller; let timer; if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") { options.signal = AbortSignal.timeout(timeoutMs); } else if (typeof AbortController !== "undefined") { controller = new AbortController(); timer = setTimeout(() => controller.abort(), timeoutMs); options.signal = controller.signal; } try { const response = await fetch(url, options); if (timer) { clearTimeout(timer); } const headers = headersToObject(response.headers); if (!response.ok) { let rawText2 = null; try { rawText2 = await response.text(); } catch { } return { status: response.status, ok: false, isJson: false, headers, data: null, raw: () => rawText2, error: `HTTP error: ${response.status} ${response.statusText}`.trim() }; } const rawText = await response.text(); try { const data = JSON.parse(rawText); return { status: response.status, ok: true, isJson: true, headers, data, raw: () => rawText }; } catch { return { status: response.status, ok: true, isJson: false, headers, data: null, raw: () => rawText, error: "Response is not valid JSON." }; } } catch (error_) { if (timer) clearTimeout(timer); return { status: 0, ok: false, isJson: false, headers: {}, data: null, raw: () => null, error: (error_ == null ? void 0 : error_.name) === "AbortError" ? "Request timed out." : `Unexpected error: ${(error_ == null ? void 0 : error_.message) || String(error_)}` }; } } function headersToObject(headers) { const result = {}; headers.forEach((value, key) => { result[key] = value; }); return result; } function baseConfigValidator(config) { if (!window) { return "Window object is not available."; } if (!config || typeof config !== "object") { return "Config: Invalid type. An object is expected."; } if (config.debug !== void 0 && typeof config.debug !== "boolean") { return "Config: Invalid debug value. Boolean expected."; } if (!config.checkoutId || typeof config.checkoutId !== "string" || !checkoutIdRegex.test(config.checkoutId)) { return "Config: Invalid checkoutId format. UUIDv4 expected."; } if ("timeout" in config && !Number.isInteger(config.timeout)) { return "Config: Invalid timeout value. A number in milliseconds is expected."; } if ("version" in config && (!config.version || !versionRegex.test(config.version))) { return `Config: Invalid version value '${config.version}'. Allowed values: ${versionRegex.toString()}`; } if (config.version && config.version === VERSION_1) { return "Config: Please upgrade to the latest version. Version 1 is no longer supported."; } return true; } function loadConfigValidator(config) { const validResponse = baseConfigValidator(config); if (validResponse !== true) { return validResponse; } if ("environment" in config && (!config.environment || !checkoutEnvironments.includes(config.environment))) { return `Config: Invalid environment value '${config.environment}'. Allowed values: ${checkoutEnvironments.join(", ")}`; } const isAsyncDefined = "async" in config; const isDeferDefined = "defer" in config; if (isAsyncDefined && typeof config.async !== "boolean") { return "Config: Invalid async value. Boolean expected."; } if (isDeferDefined && typeof config.defer !== "boolean") { return "Config: Invalid defer value. Boolean expected."; } if (config.async && config.defer) { return "Config: Only one of async or defer can be true."; } return true; } const TIMEOUT_IS_MOUNTED_DEFAULT = 1e4; const TIMEOUT_IS_MOUNTED_MIN = 500; const TIMEOUT_IS_MOUNTED_MAX = 3e4; async function loadComgateCheckout(config) { var _a, _b; const frozenConfig = Object.freeze(JSON.parse(JSON.stringify(config))); const validationResponse = loadConfigValidator(frozenConfig); if (validationResponse !== true) { return Promise.resolve({ success: false, checkoutId: frozenConfig == null ? void 0 : frozenConfig.checkoutId, error: { [MODULE_LOADER]: new TypeError(validationResponse) } }); } console.log("0 - config OK"); const env = resolveEnvironment(frozenConfig); const cdnBaseUrl = resolveUrl(frozenConfig, "cdn"); const apiBaseUrl = resolveUrl(frozenConfig, "api"); console.log("1 - resolved env, cdnUrl, apiUrn", { env, cdnBaseUrl, apiBaseUrl }); if (env !== ENVIRONMENT_PROD) { (_a = window.comgate ?? (window.comgate = {})).checkout ?? (_a.checkout = {}); (_b = window.comgate.checkout).config ?? (_b.config = {}); window.comgate.checkout.config.baseCdnUrl = cdnBaseUrl; window.comgate.checkout.config.baseApiUrl = apiBaseUrl; console.log("1.5 - ENV není DEV, mapuji baseCdnUrl a baseApiUrl na window.comgate.checkout.config", window.comgate); } const resolvedVersion = await resolveVersion(frozenConfig, cdnBaseUrl); console.log("2 - resolved version", resolvedVersion); return new Promise((resolve) => { console.log("3 - vrácen promise pro TLoadComgateCheckoutResult"); let coreLoading = null; console.log("4 - vyrábím listener a poslouchám event", moduleCore.events.ready); document.addEventListener(moduleCore.events.ready, (event) => { console.log("5 - Event zachycen", event); if (coreLoading) { handleCoreLoading({ event, resolve, coreLoading, frozenConfig, cdnBaseUrl, resolvedVersion }); } else { console.log("6 - Nepodařilo se načíst coreLoading. KONEC - CHYBA", coreLoading); resolve({ checkoutId: frozenConfig.checkoutId, success: false, error: { [MODULE_CORE]: new Error("Failed to handle Core module loading.") } }); } }); console.log("4.5 - Spousštím loadování CORE"); coreLoading = load(frozenConfig, moduleCore, cdnBaseUrl, resolvedVersion); }); } const handleCoreLoading = async (parameters) => { const loadResults = [parameters.coreLoading]; console.log("6 - Spouštím akce po úspěšném zachycení spuštěněho CORE", parameters); console.log("7 - Dump CORE modulu na window", window.comgateCheckoutCore); console.log("8 - Jdu loadovat moduly AP a GP", parameters.frozenConfig.modules); if (parameters.frozenConfig.modules !== void 0) { if (parameters.frozenConfig.modules.includes(MODULE_APPLEPAY)) { console.log("8.1 - Loaduji Apple Pay"); loadResults.push(load(parameters.frozenConfig, moduleApplePay, parameters.cdnBaseUrl, parameters.resolvedVersion)); } if (parameters.frozenConfig.modules.includes(MODULE_GOOGLEPAY)) { console.log("8.1 - Loaduji Google Pay"); loadResults.push(load(parameters.frozenConfig, moduleGooglePay, parameters.cdnBaseUrl, parameters.resolvedVersion)); } } console.log("9 - Zahajuji čekání, až budou moduly ready", loadResults); const modulesStatus = await Promise.all(loadResults); console.log("10 - Všechny moduly jsou nyní ready - promises resolved", modulesStatus); const loadResponse = { checkoutId: parameters.frozenConfig.checkoutId, success: true }; console.log("11 - Sestavuji resolve message", modulesStatus); modulesStatus.forEach((module) => { if (module.success) { loadResponse[module.name] = module.mount; } else { loadResponse.success = false; loadResponse.error = loadResponse.error || {}; loadResponse.error[module.name] = module.error; } }); if (parameters.frozenConfig.onLoad !== void 0 && typeof parameters.frozenConfig.onLoad === "function") { console.log("11.5 - Volám onLoad", loadResponse); parameters.frozenConfig.onLoad(loadResponse); } console.log("12 - Emituji even o stavu READY", EVENT_MODULES_LOADED); window.dispatchEvent(new Event(EVENT_MODULES_LOADED)); console.log("13 - Načítání resolved", loadResponse); parameters.resolve(loadResponse); }; const load = async (config, module, cdnBaseUrl, resolvedVersion) => ( // Compute hash for customUrl // const hash = config.customUrl ? await computeHash(config.customUrl) : ''; // Prepare promise new Promise((resolve) => { let resolved = false; let timeoutId; let isAsync = true; let isDeferred = false; let element = null; const isAsyncDefined = "async" in config; const isDeferDefined = "defer" in config; try { if (isAsyncDefined || isDeferDefined) { if (config.async === true) { isAsync = true; isDeferred = false; } else if (config.defer === true) { isAsync = false; isDeferred = true; } else { if (isAsyncDefined) { isAsync = Boolean(config.async); } if (isDeferDefined) { isDeferred = Boolean(config.defer); } } } const loadId = `cg-load-checkout-${module.name.toLowerCase()}`; element = document.querySelector(`#${loadId}`); if (element) { if (getElementData(element, "success") === MODULE_LOAD_SUCCESSFULLY) { setElementData(element, "success", resolveModuleLoad(resolve, module) ? MODULE_LOAD_SUCCESSFULLY : MODULE_LOAD_FAILED); } else { element.remove(); element = null; } } if (!element) { const script = createScriptElement(loadId, resolvedVersion, isAsync, isDeferred, cdnBaseUrl, module.file); script.addEventListener("error", (error) => { if (!resolved) { resolved = true; clearTimeout(timeoutId); setElementData(script, "success", MODULE_LOAD_FAILED); resolve({ success: false, name: module.name, error: new Error("Failed to load script.", { cause: error }) }); } }); const timeout = validateNumber(config.timeout, TIMEOUT_IS_MOUNTED_MIN, TIMEOUT_IS_MOUNTED_MAX, TIMEOUT_IS_MOUNTED_DEFAULT); timeoutId = window.setTimeout(() => { if (!resolved) { resolved = true; clearTimeout(timeoutId); const mountObject = getReturnObject(module); if (!mountObject) { setElementData(script, "success", MODULE_LOAD_FAILED); resolve({ success: false, name: module.name, error: new Error("Timeout reached.") }); return; } setElementData(script, "success", MODULE_LOAD_SUCCESSFULLY); resolve({ success: true, name: module.name, mount: mountObject }); } }, timeout); document.addEventListener(module.events.ready, () => { if (!resolved) { resolved = true; clearTimeout(timeoutId); setElementData(script, "success", resolveModuleLoad(resolve, module) ? MODULE_LOAD_SUCCESSFULLY : MODULE_LOAD_FAILED); } }); document.head.append(script); } else if (!resolved) { resolved = true; clearTimeout(timeoutId); setElementData(element, "success", resolveModuleLoad(resolve, module) ? MODULE_LOAD_SUCCESSFULLY : MODULE_LOAD_FAILED); } } catch (error) { if (!resolved) { resolved = true; setElementData(element, "success", MODULE_LOAD_FAILED); resolve({ success: false, name: module.name, error: new Error("Unexpected error.", { cause: error }) }); } } }) ); const resolveModuleLoad = (resolve, module) => { const mountObject = getReturnObject(module); if (!mountObject) { resolve({ success: false, name: module.name, error: new Error(`The module does not mount correctly. Path window.${module.mountPoint.join(".")} is undefined.`) }); return false; } resolve({ success: true, name: module.name, mount: mountObject }); return true; }; const getReturnObject = (module) => { const moduleObject = module.mountPoint.reduce((accumulator, currentValue) => accumulator == null ? void 0 : accumulator[currentValue], window); if (validateModuleObject(moduleObject)) { return moduleObject; } return void 0; }; const validateModuleObject = (object) => object && typeof object == "object" && "create" in object && typeof object.create == "function" && "version" in object && typeof object.version == "function"; function prefetchConfigValidator(config) { const validResponse = baseConfigValidator(config); if (validResponse !== true) { return validResponse; } return true; } async function prefetchComgateCheckout(config) { const frozenConfig = Object.freeze(JSON.parse(JSON.stringify(config))); const validationResponse = prefetchConfigValidator(frozenConfig); if (validationResponse !== true) { return Promise.resolve({ success: false, checkoutId: frozenConfig == null ? void 0 : frozenConfig.checkoutId, prefetched: [], error: { [MODULE_LOADER]: new TypeError(validationResponse) } }); } const cdnBaseUrl = resolveUrl(frozenConfig, "cdn"); const resolvedVersion = await resolveVersion(frozenConfig, cdnBaseUrl); const prefetchResults = []; if (frozenConfig.excludeCore !== true) { prefetchResults.push(prefetch(frozenConfig, moduleCore, cdnBaseUrl, resolvedVersion)); } if (frozenConfig.modules !== void 0) { if (frozenConfig.modules.includes(MODULE_APPLEPAY)) { prefetchResults.push(prefetch(frozenConfig, moduleApplePay, cdnBaseUrl, resolvedVersion)); } if (frozenConfig.modules.includes(MODULE_GOOGLEPAY)) { prefetchResults.push(prefetch(frozenConfig, moduleGooglePay, cdnBaseUrl, resolvedVersion)); } } const modulesStatus = await Promise.all(prefetchResults); const prefetchResponse = { checkoutId: frozenConfig.checkoutId, prefetched: [], success: true }; modulesStatus.forEach((module) => { if (module.success) { prefetchResponse.prefetched.push(module.name); } else { prefetchResponse.success = false; prefetchResponse.error = prefetchResponse.error || {}; prefetchResponse.error[module.name] = module.error; } }); if (frozenConfig.onPrefetch !== void 0 && typeof frozenConfig.onPrefetch === "function") { frozenConfig.onPrefetch(prefetchResponse); } window.dispatchEvent(new Event(EVENT_MODULES_PREFETCHED)); return prefetchResponse; } const prefetch = async (config, module, cdnBaseUrl, resolvedVersion) => new Promise((resolve) => { let resolved = false; let isLoaded = false; let timeoutId; let element = null; try { const prefetchId = `cg-prefetch-checkout-${module.name.toLowerCase()}`; element = document.querySelector(`#${prefetchId}`); if (element && getElementData(element, "success") !== MODULE_LOAD_SUCCESSFULLY) { element.remove(); element = null; } if (!element) { const prefetch2 = createPrefetchLinkElement(prefetchId, resolvedVersion, cdnBaseUrl, module.file); prefetch2.addEventListener("load", () => { if (!resolved) { resolved = true; setElementData(prefetch2, "success", MODULE_LOAD_SUCCESSFULLY); clearTimeout(timeoutId); isLoaded = true; resolve({ success: true, name: module.name }); } }); prefetch2.addEventListener("error", (error) => { if (!resolved) { resolved = true; clearTimeout(timeoutId); setElementData(prefetch2, "success", MODULE_LOAD_FAILED); resolve({ success: false, name: module.name, error: new Error("Failed to prefetch script.", { cause: error }) }); } }); const timeout = validateNumber(config.timeout, 500, 3e4, 1e4); timeoutId = window.setTimeout(() => { if (!resolved) { resolved = true; setElementData(prefetch2, "success", isLoaded ? MODULE_LOAD_SUCCESSFULLY : MODULE_LOAD_FAILED); resolve({ success: isLoaded, name: module.name, ...isLoaded ? {} : { error: new Error("Timeout reached.") } }); } }, timeout); document.head.append(prefetch2); } else if (!resolved) { resolved = true; resolve({ success: true, name: module.name }); } } catch (error) { if (!resolved) { resolved = true; setElementData(element, "success", MODULE_LOAD_FAILED); clearTimeout(timeoutId); resolve({ success: false, name: module.name, error: new Error("Unexpected error.", { cause: error }) }); } } }); const version = "2.0.4"; const revision = "5a815b2"; function getLoaderVersion() { return { version, revision }; } export { MODULE_APPLEPAY, MODULE_CORE, MODULE_GOOGLEPAY, MODULE_LOADER, VERSION_1, VERSION_2, VERSION_DEV, VERSION_PREFERRED, checkoutIdRegex, checkoutVersions, getLoaderVersion, loadComgateCheckout, prefetchComgateCheckout, versionRegex }; //# sourceMappingURL=comgate-checkout-js-dev.es.js.map