UNPKG

@comgate/checkout-js

Version:

Loading wrapper for Comgate Checkout library.

1,002 lines (1,001 loc) 34.8 kB
/* * @comgate/checkout-js v3.0.1 (https://www.npmjs.com/package/@comgate/checkout-js) * Copyright 2026 - Comgate a.s. * Licensed under EULA (https://www.unpkg.com/@comgate/checkout-js@3.0.1/LICENSE) * Build datetime - 2026-06-11T05:57:52Z */ const VERSION_DEV = "dev"; const VERSION_1 = "1"; const VERSION_2 = "2"; const VERSION_3 = "3"; 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 TIMEOUT_LOAD_DEFAULT = 1e4; const TIMEOUT_LOAD_MIN = 500; const TIMEOUT_LOAD_MAX = 3e4; const TIMEOUT_FETCH_DEFAULT = 5e3; const TIMEOUT_FETCH_MIN = 500; const TIMEOUT_FETCH_MAX = 15e3; const checkoutEnvironments = [ENVIRONMENT_DEV, ENVIRONMENT_TEST, ENVIRONMENT_PROD]; const VERSION_PREFERRED = VERSION_3; const checkoutVersions = [VERSION_2, VERSION_3, 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(`^([23]\.[0-9]+\.[0-9]+|${checkoutVersions.join("|")})$`, "i"); const semverRegex = new RegExp(`^([23]\.[0-9]+\.[0-9]+)$`, "i"); const MODULE_LOADER = "loader"; const MODULE_CORE = "core"; const FILE_MODULE_CORE = "checkout-core.min.js"; const moduleCore = { boundName: "comgateCheckoutCore", 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 = { boundName: "comgateCheckoutApplePay", 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 = { boundName: "comgateCheckoutGooglePay", name: MODULE_GOOGLEPAY, events: { ready: "ComgateCheckoutGooglePayLoaded" }, mountPoint: ["comgate", "checkout", "googlepay"], file: FILE_MODULE_GOOGLEPAY }; const MODULE_CARD = "card"; const FILE_MODULE_CARD = "checkout-card.min.js"; const moduleCard = { boundName: "comgateCheckoutCard", name: MODULE_CARD, events: { ready: "ComgateCheckoutCardLoaded" }, mountPoint: ["comgate", "checkout", "card"], file: FILE_MODULE_CARD }; const EVENT_MODULES_LOADED = "comgate-checkout-js-module-loaded"; const MODULE_LOAD_SUCCESSFULLY = "true"; const MODULE_LOAD_FAILED = "false"; const outerModuleList = [MODULE_CORE, MODULE_APPLEPAY, MODULE_GOOGLEPAY, MODULE_CARD]; 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 createPreloadLinkElement = (preloadId, version2, baseUrl, file) => { const preload2 = document.createElement("link"); preload2.id = preloadId; preload2.rel = "preload"; preload2.as = "script"; preload2.href = resolveFileUrl(baseUrl, version2, file); return preload2; }; 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 doesModuleAlreadyExist = (moduleConfig) => { return moduleConfig.boundName in window; }; const getModuleMountObject = (moduleConfig) => { const moduleObject = moduleConfig.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"; const resolveDebug = (config) => { return config.debug === true; }; const resolveEnvironment = (config) => { return ("environment" in config ? config.environment : ENVIRONMENT_PREFERRED) || ENVIRONMENT_PREFERRED; }; 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 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) => { if (config.version === VERSION_1 || config.version && /^1\.\d+\.\d+$/.test(config.version)) { throw new Error("Checkout SDK: Version 1 is no longer supported. Please use version 2 or 3."); } 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: Invalid versions.json response, using cdn fallback.", { url: cdnBaseUrl + "versions.json", error: res == null ? void 0 : res.error }); } }).catch((error) => { if (resolveDebug(config)) { console.warn("Checkout SDK: can't fetch versions.json, using cdn fallback.", { url: cdnBaseUrl + "versions.json", 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 }; } async function safeFetch(url, options = {}, timeout = 1e4) { const timeoutMs = validateNumber(timeout, TIMEOUT_FETCH_MIN, TIMEOUT_FETCH_MAX, TIMEOUT_FETCH_DEFAULT); let controller; let timer; if (AbortSignal !== void 0 && typeof AbortSignal.timeout === "function") { options.signal = AbortSignal.timeout(timeoutMs); } else if (AbortController !== void 0) { 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 validateNumber(value, min, max, defaultValue) { if (value && typeof value === "number") { if (value < min) { return min; } if (value > max) { return max; } return value; } return defaultValue; } function buildElementId(elementType, name) { return `cg-${elementType}-checkout-${name.toLowerCase()}`; } function baseConfigValidator(config) { if (!window) { return "Window object is not available. Please ensure you are running this in a valid browser environment."; } if (typeof window !== "object") { return "Invalid window type. An object is expected. Please ensure you are running this in a valid browser environment."; } if (!config || typeof config !== "object") { return "Config: Invalid type. An object is expected."; } if ("debug" in config && 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 || typeof config.version !== "string" || !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."; } if (!("modules" in config) || !Array.isArray(config.modules)) { return `Config: The "modules" property must be provided as an array. Allowed values: ${outerModuleList.join(", ")}.`; } if (config.modules.length === 0 || config.modules.length === 1 && config.modules.includes(MODULE_CORE)) { return `Config: No modules have been provided. At least one module is required (excluding core). Allowed values: ${outerModuleList.join(", ")}.`; } const invalid = config.modules.find((m) => !outerModuleList.includes(m)); if (invalid !== void 0) { return `Config: Invalid module value '${invalid}'. Allowed values: ${outerModuleList.join(", ")}.`; } return true; } function preloadConfigValidator(config) { const validResponse = baseConfigValidator(config); if (validResponse !== true) { return validResponse; } return true; } async function preloadComgateCheckout(config) { const validationResponse = preloadConfigValidator(config); if (validationResponse !== true) { return Promise.reject({ success: false, checkoutId: config == null ? void 0 : config.checkoutId, preloaded: [], error: { [MODULE_LOADER]: new TypeError(validationResponse) } }); } const frozenConfig = Object.freeze(JSON.parse(JSON.stringify(config))); const cdnBaseUrl = resolveUrl(frozenConfig, "cdn"); const resolvedVersion = await resolveVersion(frozenConfig, cdnBaseUrl); return new Promise((resolve, reject) => { const preloadResults = []; if (frozenConfig.excludeCore !== true) { preloadResults.push(preload({ config: frozenConfig, module: moduleCore, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules !== void 0) { if (frozenConfig.modules.includes(MODULE_APPLEPAY)) { preloadResults.push(preload({ config: frozenConfig, module: moduleApplePay, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules.includes(MODULE_GOOGLEPAY)) { preloadResults.push(preload({ config: frozenConfig, module: moduleGooglePay, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules.includes(MODULE_CARD)) { preloadResults.push(preload({ config: frozenConfig, module: moduleCard, cdnBaseUrl, resolvedVersion })); } } Promise.all(preloadResults).then((modulesStatus) => { const preloadResponse = { checkoutId: frozenConfig.checkoutId, preloaded: [], success: true }; modulesStatus.forEach((module) => { if (module.success) { preloadResponse.preloaded.push(module.name); } else { preloadResponse.success = false; preloadResponse.error = preloadResponse.error || {}; preloadResponse.error[module.name] = module.error; } }); if (frozenConfig.onPreload !== void 0 && typeof frozenConfig.onPreload === "function") { frozenConfig.onPreload(preloadResponse); } if (preloadResponse.success) { resolve(preloadResponse); return; } reject(preloadResponse); }); }); } const isModuleLoaded$1 = (module) => { const moduleLoadId = buildElementId("load", module.name); const element = document.querySelector(`#${moduleLoadId}`); if (element) { const success = getElementData(element, "success"); if (success === MODULE_LOAD_SUCCESSFULLY) { return true; } } return false; }; const preload = async (preloadConfig) => new Promise((resolve, reject) => { let element = null; try { if (isModuleLoaded$1(preloadConfig.module)) { resolve({ success: true, name: preloadConfig.module.name }); return; } const preloadId = buildElementId("preload", preloadConfig.module.name); element = document.querySelector(`#${preloadId}`); if (element) { resolve({ success: true, name: preloadConfig.module.name }); } else { const preload2 = createPreloadLinkElement(preloadId, preloadConfig.resolvedVersion, preloadConfig.cdnBaseUrl, preloadConfig.module.file); document.head.append(preload2); resolve({ success: true, name: preloadConfig.module.name }); } } catch (error) { setElementData(element, "success", MODULE_LOAD_FAILED); reject({ success: false, name: preloadConfig.module.name, error: new Error("Unexpected error.", { cause: error }) }); } }); 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 may be set to true."; } return true; } async function loadComgateCheckout(config) { var _a, _b; const validationResponse = loadConfigValidator(config); if (validationResponse !== true) { return Promise.reject({ success: false, checkoutId: config == null ? void 0 : config.checkoutId, error: { [MODULE_LOADER]: new TypeError(validationResponse) } }); } const frozenConfig = Object.freeze(JSON.parse(JSON.stringify(config))); const env = resolveEnvironment(frozenConfig); const cdnBaseUrl = resolveUrl(frozenConfig, "cdn"); const apiBaseUrl = resolveUrl(frozenConfig, "api"); (_a = window.comgate ?? (window.comgate = {})).checkout ?? (_a.checkout = {}); window.comgate.checkout.checkoutId = frozenConfig.checkoutId; (_b = window.comgate.checkout).config ?? (_b.config = {}); if (env !== ENVIRONMENT_PROD) { window.comgate.checkout.config.baseCdnUrl = cdnBaseUrl; window.comgate.checkout.config.baseApiUrl = apiBaseUrl; window.comgate.checkout.config.environment = env; } const resolvedVersion = await resolveVersion(frozenConfig, cdnBaseUrl); window.comgate.checkout.config.version = resolvedVersion.version; return new Promise((resolve, reject) => { let coreLoading = null; if (doesModuleAlreadyExist(moduleCore)) { coreLoading = Promise.resolve({ success: true, name: moduleCore.name, mount: getModuleMountObject(moduleCore) }); handleCoreLoading({ event: null, resolve, reject, coreLoading, frozenConfig, cdnBaseUrl, resolvedVersion }); return; } document.addEventListener(moduleCore.events.ready, (event) => { if (coreLoading) { handleCoreLoading({ event, resolve, reject, coreLoading, frozenConfig, cdnBaseUrl, resolvedVersion }); } else { reject({ checkoutId: frozenConfig.checkoutId, success: false, error: { [MODULE_CORE]: new Error("Failed to handle Core module loading.") } }); } }); coreLoading = load(frozenConfig, moduleCore, cdnBaseUrl, resolvedVersion).catch((error) => { reject({ checkoutId: frozenConfig.checkoutId, success: false, error: { [MODULE_CORE]: new Error("Failed to handle Core module loading.", { cause: JSON.stringify(error) }) } }); return Promise.resolve({ success: false, name: MODULE_CORE, error: new Error("Failed to handle Core module loading.", { cause: error }) }); }); preloadComgateCheckout({ ...config, excludeCore: true }); }); } const handleCoreLoading = async (parameters) => { const loadResults = [parameters.coreLoading]; if (parameters.frozenConfig.modules !== void 0) { if (parameters.frozenConfig.modules.includes(MODULE_APPLEPAY)) { loadResults.push(load(parameters.frozenConfig, moduleApplePay, parameters.cdnBaseUrl, parameters.resolvedVersion)); } if (parameters.frozenConfig.modules.includes(MODULE_GOOGLEPAY)) { loadResults.push(load(parameters.frozenConfig, moduleGooglePay, parameters.cdnBaseUrl, parameters.resolvedVersion)); } if (parameters.frozenConfig.modules.includes(MODULE_CARD)) { loadResults.push(load(parameters.frozenConfig, moduleCard, parameters.cdnBaseUrl, parameters.resolvedVersion)); } } const modulesStatus = await Promise.all(loadResults); const loadResponse = { checkoutId: parameters.frozenConfig.checkoutId, success: true }; 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") { parameters.frozenConfig.onLoad(loadResponse); } window.dispatchEvent(new Event(EVENT_MODULES_LOADED)); if (loadResponse.success) { parameters.resolve(loadResponse); } else { parameters.reject(loadResponse); } }; const load = async (config, module, cdnBaseUrl, resolvedVersion) => new Promise((resolve, reject) => { 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 = buildElementId("load", module.name); 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); reject({ success: false, name: module.name, error: `Failed to load script: ${JSON.stringify(error)}` }); } }); const timeout = validateNumber(config.timeout, TIMEOUT_LOAD_MIN, TIMEOUT_LOAD_MAX, TIMEOUT_LOAD_DEFAULT); timeoutId = window.setTimeout(() => { if (!resolved) { resolved = true; clearTimeout(timeoutId); const mountObject = getModuleMountObject(module); if (!mountObject) { setElementData(script, "success", MODULE_LOAD_FAILED); reject({ 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); reject({ success: false, name: module.name, error: new Error("Unexpected error.", { cause: error }) }); } } }); const resolveModuleLoad = (onResolve, module) => { const mountObject = getModuleMountObject(module); if (!mountObject) { onResolve({ success: false, name: module.name, error: new Error(`The module does not mount correctly. Path window.${module.mountPoint.join(".")} is undefined.`) }); return false; } onResolve({ success: true, name: module.name, mount: mountObject }); return true; }; function prefetchConfigValidator(config) { const validResponse = baseConfigValidator(config); if (validResponse !== true) { return validResponse; } return true; } async function prefetchComgateCheckout(config) { const validationResponse = prefetchConfigValidator(config); if (validationResponse !== true) { return Promise.reject({ success: false, checkoutId: config == null ? void 0 : config.checkoutId, prefetched: [], error: { [MODULE_LOADER]: new TypeError(validationResponse) } }); } const frozenConfig = Object.freeze({ ...JSON.parse(JSON.stringify(config)), onPrefetch: config.onPrefetch }); const cdnBaseUrl = resolveUrl(frozenConfig, "cdn"); const resolvedVersion = await resolveVersion(frozenConfig, cdnBaseUrl); return new Promise((resolve, reject) => { const prefetchResults = []; if (frozenConfig.excludeCore !== true) { prefetchResults.push(prefetch({ config: frozenConfig, module: moduleCore, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules !== void 0) { if (frozenConfig.modules.includes(MODULE_APPLEPAY)) { prefetchResults.push(prefetch({ config: frozenConfig, module: moduleApplePay, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules.includes(MODULE_GOOGLEPAY)) { prefetchResults.push(prefetch({ config: frozenConfig, module: moduleGooglePay, cdnBaseUrl, resolvedVersion })); } if (frozenConfig.modules.includes(MODULE_CARD)) { prefetchResults.push(prefetch({ config: frozenConfig, module: moduleCard, cdnBaseUrl, resolvedVersion })); } } Promise.all(prefetchResults).then((modulesStatus) => { 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); } if (prefetchResponse.success) { resolve(prefetchResponse); return; } reject(prefetchResponse); }); }); } const isModuleLoaded = (module) => { const moduleLoadId = buildElementId("load", module.name); const element = document.querySelector(`#${moduleLoadId}`); if (element) { const success = getElementData(element, "success"); if (success === MODULE_LOAD_SUCCESSFULLY) { return true; } } return false; }; const prefetch = async (prefetchConfig) => new Promise((resolve, reject) => { let element = null; try { if (isModuleLoaded(prefetchConfig.module)) { resolve({ success: true, name: prefetchConfig.module.name }); return; } const prefetchId = buildElementId("prefetch", prefetchConfig.module.name); element = document.querySelector(`#${prefetchId}`); if (element) { resolve({ success: true, name: prefetchConfig.module.name }); } else { const link = createPrefetchLinkElement(prefetchId, prefetchConfig.resolvedVersion, prefetchConfig.cdnBaseUrl, prefetchConfig.module.file); document.head.append(link); resolve({ success: true, name: prefetchConfig.module.name }); } } catch (error) { setElementData(element, "success", MODULE_LOAD_FAILED); reject({ success: false, name: prefetchConfig.module.name, error: new Error("Unexpected error.", { cause: error }) }); } }); const version = "3.0.1"; const revision = "839976af"; function getLoaderVersion() { return { version, revision }; } const MAX_WAIT_FRAMES = 5; function waitForSelector(selector) { let frame = 0; return new Promise((resolve) => { function check() { const elements = document.querySelectorAll(selector); if (elements.length > 0) { resolve(elements); return; } frame++; if (frame >= MAX_WAIT_FRAMES) { resolve(null); return; } requestAnimationFrame(check); } requestAnimationFrame(check); }); } async function resolveMountPoint(mountPoint, moduleId) { const tag = `[ComgateCheckout](${moduleId}):`; if (mountPoint === void 0 || mountPoint === null) { throw new Error( `${tag} Mount point is required but was not provided. Pass a CSS selector string (e.g. "#my-container") or a direct HTMLDivElement reference.` ); } if (typeof mountPoint === "string") { let elements = document.querySelectorAll(mountPoint); if (elements.length === 0) { const delayed = await waitForSelector(mountPoint); if (delayed === null) { throw new Error(`${tag} Mount point selector "${mountPoint}" did not match any element in the DOM.`); } elements = delayed; } if (elements.length > 1) { throw new Error(`${tag} Mount point selector "${mountPoint}" matched ${elements.length} elements — must match exactly one.`); } const element = elements[0]; if (!(element instanceof HTMLDivElement)) { throw new TypeError( `${tag} Mount point selector "${mountPoint}" matched an element that is not a <div> (got <${element.tagName.toLowerCase()}>).` ); } if (!element.id) { throw new Error(`${tag} Mount point element matched by "${mountPoint}" must have a non-empty "id" attribute.`); } return { element, id: element.id }; } if (!mountPoint.isConnected) { throw new Error(`${tag} Mount point element is not connected to the DOM.`); } if (!mountPoint.id) { throw new Error(`${tag} Mount point element must have a non-empty "id" attribute.`); } return { element: mountPoint, id: mountPoint.id }; } function errorMessage(error) { if (error instanceof Error) return error.message; return String(error); } async function initModule(moduleName, loaderModule, create, mountPoint) { if (!loaderModule) { return { success: false, error: `${moduleName} module was not loaded`, instance: null }; } let instance; try { instance = await create(loaderModule); } catch (error) { return { success: false, error: errorMessage(error), instance: null }; } try { await instance.canMakePayments(); const { element } = await resolveMountPoint(mountPoint, instance.getModuleId()); try { await instance.mount(element); } finally { element.classList.remove("is-loading"); } return { success: true, instance, error: void 0 }; } catch (error) { return { success: false, error: errorMessage(error), instance }; } } async function useCheckout(config) { if (!config.checkoutId || !checkoutIdRegex.test(config.checkoutId)) { throw new Error(`Invalid checkoutId: "${config.checkoutId}"`); } if (!config.core) { throw new Error('Missing required "core" configuration in useCheckout().'); } const modules = [MODULE_CORE]; if (config.applepay) modules.push(MODULE_APPLEPAY); if (config.googlepay) modules.push(MODULE_GOOGLEPAY); if (config.card) modules.push(MODULE_CARD); const loadResult = await loadComgateCheckout({ checkoutId: config.checkoutId, modules, version: config.version ?? VERSION_3, environment: config.environment ?? ENVIRONMENT_PROD, debug: config.debug ?? false }); if (!loadResult.core) { throw new Error("Core module is not available after loading"); } const coreInstance = await loadResult.core.create({ ...config.core, checkoutId: config.checkoutId, debug: config.debug ?? false, env: config.environment ?? ENVIRONMENT_PROD }); const [apResult, gpResult, cardResult] = await Promise.all([ config.applepay ? initModule( "Apple Pay", loadResult.applepay, (m) => m.create(coreInstance, config.applepay), config.applepay.mountPoint ) : Promise.resolve(void 0), config.googlepay ? initModule( "Google Pay", loadResult.googlepay, (m) => m.create(coreInstance, config.googlepay), config.googlepay.mountPoint ) : Promise.resolve(void 0), config.card ? initModule("Card", loadResult.card, (m) => m.create(coreInstance, config.card), config.card.mountPoint) : Promise.resolve(void 0) ]); const overallSuccess = [apResult, gpResult, cardResult].filter((r) => r !== void 0).every((r) => r.success); return { success: overallSuccess, core: { success: true, instance: coreInstance, error: void 0 }, applepay: config.applepay ? apResult ?? { success: false, error: "Unknown error", instance: null } : void 0, googlepay: config.googlepay ? gpResult ?? { success: false, error: "Unknown error", instance: null } : void 0, card: config.card ? cardResult ?? { success: false, error: "Unknown error", instance: null } : void 0 }; } export { ENVIRONMENT_DEV, ENVIRONMENT_PREFERRED, ENVIRONMENT_PROD, ENVIRONMENT_TEST, MODULE_APPLEPAY, MODULE_CARD, MODULE_CORE, MODULE_GOOGLEPAY, MODULE_LOADER, VERSION_1, VERSION_2, VERSION_3, VERSION_DEV, VERSION_PREFERRED, checkoutIdRegex, checkoutVersions, getLoaderVersion, loadComgateCheckout, prefetchComgateCheckout, preloadComgateCheckout, useCheckout, versionRegex }; //# sourceMappingURL=comgate-checkout-js.es.js.map