diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..73dcc67 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "globals": { + "$": "readonly", + "jQuery": "readonly" + }, + "extends": ["eslint:recommended"], + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "warn", + "no-undef": "warn", + "semi": "off", + "no-empty": "off", + "no-extra-semi": "off", + "no-unsafe-optional-chaining": "off", + "no-redeclare": "off", + "no-constant-condition": "off" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bacfd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +.DS_Store + +# Build artifacts +/dist/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..051416d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "proseWrap": "preserve", + "singleQuote": true +} diff --git a/README.md b/README.md index fd61012..4f8bf24 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -
@@ -12,7 +11,6 @@ KeydropPlus v2 is an unofficial extension for [keydrop.com](https://key-drop.com/) that adds new features and improves the user interface. - ## 💡 List of current functions - Automatic joining of 'Amateur' giveaways [Does not work on reCATCH]. @@ -27,7 +25,6 @@ KeydropPlus v2 is an unofficial extension for [keydrop.com](https://key-drop.com - Display of pre-selected user giveaways. - Automatic clicking on the receive gold code button at the 'direct link' (?code=). - ## 📁 How to add an extension 1. Extract the files to a folder @@ -36,7 +33,6 @@ KeydropPlus v2 is an unofficial extension for [keydrop.com](https://key-drop.com 4. Click the "Upload unzipped" button 5. Select the folder with the extracted extension - ## 🌐 Works on these browsers - Google Chrome @@ -46,7 +42,6 @@ KeydropPlus v2 is an unofficial extension for [keydrop.com](https://key-drop.com - Brave Browser - And others based on Chromium - ## 🌍 Available languages - English @@ -56,13 +51,14 @@ KeydropPlus v2 is an unofficial extension for [keydrop.com](https://key-drop.com ## 🛠️ Configuration - Correctly setting prices from Steam To get everything working without a problem, you need to: + - Set the currency on the key-drop page to PLN, EUR or USD - Log in to Steam in your browser and set the currency to PLN, EUR or USD _Refreshing prices too often can temporarily block the Steam Market API._ - ## ✨ Usage + - [Keydrop API](key-drop.com) - [Steam API](https://steamcommunity.com/market/) - [Skinport API](https://docs.skinport.com/#introduction) @@ -70,7 +66,6 @@ _Refreshing prices too often can temporarily block the Steam Market API._ - [jQuery](https://jquery.com) - [Chart.js](https://github.com/chartjs/Chart.js) - ## 🔥 Screenshots ![Case Stats](https://github.com/Juzlus/KeydropPlus/assets/41649887/5146506d-d09d-4513-ac96-f69cab0f2b46) @@ -78,13 +73,28 @@ _Refreshing prices too often can temporarily block the Steam Market API._ ![Fast Case Battle](https://github.com/Juzlus/KeydropPlus/assets/41649887/45e23d0b-6921-4efd-9731-c9cb62b7c138) ![User Statistics](https://github.com/Juzlus/KeydropPlus/assets/41649887/72eeef42-09a5-44eb-a13d-75f7d42ec80a) +## 🧑‍💻 Development + +This project uses Node.js tooling to keep the codebase consistent. + +```bash +npm install # install dependencies +npm run lint # check JavaScript style +npm run format # verify formatting +``` + +## 🤝 Contributing + +Issues and feature requests are tracked on the [GitHub issue tracker](https://github.com/Juzlus/KeydropPlus/issues). + +Pull requests are welcome! Please fork the repository, create a topic branch for your work and open a pull request. Remember to run the linter and formatter before submitting. ## 📝 Feedback If you have any Feedback or questions, please contact me at juzlus.biznes@gmail.com or [Discord](https://discordapp.com/users/284780352042434570). - ## 💝 Donate + @@ -95,10 +105,8 @@ If you have any Feedback or questions, please contact me at juzlus.biznes@gmail. - ## ⚠️ Disclaimer _The KeydropPlus v2 is an independent project developed by an individual and is not endorsed or affiliated with [key-drop.com](https://key-drop.com/)._ _The author of the extension is not responsible for any consequences resulting from its use._ - diff --git a/css/style.css b/css/style.css index 0fddac2..fcafe02 100644 --- a/css/style.css +++ b/css/style.css @@ -346,13 +346,23 @@ tbody .fullTd { } .keydorp-plus-change-language { + display: inline-block; + height: 34px; + cursor: pointer; + filter: opacity(0.5); transition: 0.25s; } -.keydorp-plus-change-language:hover { +.keydorp-plus-change-language:hover, +.keydorp-plus-change-language.active { filter: opacity(1) !important; } +.keydorp-plus-change-language.active { + border: 1px solid gold; + border-radius: 4px; +} + div.hidden.overflow-hidden.md\:block.bg-navy-700 { height: 76px; } diff --git a/data/lang/english.json b/data/lang/english.json index 7cff24a..3bea35b 100644 --- a/data/lang/english.json +++ b/data/lang/english.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "You can only join up to 20 giveaways per day", "autogiveaway_settings_p5": "Minimum Amount", "autogiveaway_settings_a5": "Minimum amount of the giveaway", + "autogiveaway_settings_p6": "Search pages", + "autogiveaway_settings_a6": "Number of pages to scan for giveaways", "autogiveaway_settings_p3": "Won Giveaways", "autogiveaway_settings_a3": "Counted won giveaways", "autogiveaway_settings_p4": "Earnings from Giveaways", diff --git a/data/lang/polish.json b/data/lang/polish.json index f94073e..45ea971 100644 --- a/data/lang/polish.json +++ b/data/lang/polish.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "Codziennie można dołączyć tylko do 20 konkursów", "autogiveaway_settings_p5": "Minimalna kwota", "autogiveaway_settings_a5": "Minimalna kwota konkursu", + "autogiveaway_settings_p6": "Liczba stron", + "autogiveaway_settings_a6": "Ilość stron do przeszukania konkursów", "autogiveaway_settings_p3": "Wygrane konkursy", "autogiveaway_settings_a3": "Zliczone wygrane konkursy", "autogiveaway_settings_p4": "Zarobek z konkursów", diff --git a/data/lang/portuguese.json b/data/lang/portuguese.json index e5b4ca7..1c8f6e8 100644 --- a/data/lang/portuguese.json +++ b/data/lang/portuguese.json @@ -22,6 +22,8 @@ "autogiveaway_settings_a2": "Você só pode participar de até 20 sorteios por dia", "autogiveaway_settings_p5": "Quantidade mínima", "autogiveaway_settings_a5": "Quantidade mínima do sorteio", + "autogiveaway_settings_p6": "Páginas de busca", + "autogiveaway_settings_a6": "Número de páginas para procurar sorteios", "autogiveaway_settings_p3": "Sorteios Ganhos", "autogiveaway_settings_a3": "Número de sorteios ganhos", "autogiveaway_settings_p4": "Ganhos com sorteios", diff --git a/js/caseInfo.js b/js/caseInfo.js index 04b3645..ebb245b 100644 --- a/js/caseInfo.js +++ b/js/caseInfo.js @@ -295,7 +295,7 @@ const caseDataCombine = async(caseJSON, languageText) => { const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; const goldenCases = cases?.filter(el => el?.goldProfit !== undefined); diff --git a/js/caseOdds.js b/js/caseOdds.js index 864e9a9..ab973ac 100644 --- a/js/caseOdds.js +++ b/js/caseOdds.js @@ -2,7 +2,7 @@ $( document ).ready(async() => { const config = await getConfigData(); const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch || !config) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; waitForElm('section#gold-area').then(async() => { @@ -20,6 +20,22 @@ $( document ).ready(async() => { addObserverIfDesiredNodeAvailable(); }); +const goldProfitThresholds = [ + { max: 11111111, label: '0/5' }, + { max: 13209876, label: '0.5/5' }, + { max: 15308641, label: '1/5' }, + { max: 17407407, label: '1.5/5' }, + { max: 19506172, label: '2/5' }, + { max: 21604937, label: '2.5/5' }, + { max: 23703703, label: '3/5' }, + { max: 25802468, label: '3.5/5' }, + { max: 27901233, label: '4/5' }, + { max: 29999999, label: '4.5/5' }, + { max: Infinity, label: '5/5' }, +]; + +const calculateGoldOdds = (profit) => goldProfitThresholds.find(t => profit <= t.max).label; + const refreshOdds = async(config, cases, init) => { const index = await getIndexData(); const currencyRates = index?.currencyRates; @@ -62,49 +78,23 @@ const createCaseOdds = async(config, currentRate, currency, cases, thisElement, const caseName = $(thisElement)?.find('div[data-testid=case-card-badge-btn] p')?.last()?.text(); if(!caseName) return; - let odds; const jokerCase = config?.showJokerOdds ? cases?.filter(el => el?.name == `${caseName} JOKER`) : null; - const thisCase = config?.showJokerOdds && jokerCase && jokerCase?.length ? jokerCase : cases?.filter(el => el?.name == caseName); - if(!thisCase || !thisCase?.length) return; - if (thisCase[0]?.goldProfit !== undefined) { - const profit = thisCase[0]?.goldProfit; - if(profit <= 11111111) - odds = `0/5`; - else if(profit <= 13209876) - odds = `0.5/5`; - else if(profit <= 15308641) - odds = `1/5`; - else if(profit <= 17407407) - odds = `1.5/5`; - else if(profit <= 19506172) - odds = `2/5`; - else if(profit <= 21604937) - odds = `2.5/5`; - else if(profit <= 23703703) - odds = `3/5`; - else if(profit <= 25802468) - odds = `3.5/5`; - else if(profit <= 27901233) - odds = `4/5`; - else if(profit <= 29999999) - odds = `4.5/5`; - else - odds = `5/5`; - } else - odds = `${thisCase[0]?.odds}%`; - - const isJoker = thisCase[0]?.name?.endsWith(' JOKER') || false; - const cardEl = $(thisElement)?.find(eventCase ? 'div[data-testid="case-card-price-btn"]' : 'div.absolute.right-3.rounded.bg-navy-900.px-3.text-xs.font-semibold.text-gold-500') - ?.eq(0); - + const thisCaseArr = config?.showJokerOdds && jokerCase && jokerCase?.length ? jokerCase : cases?.filter(el => el?.name == caseName); + const caseData = thisCaseArr?.[0]; + if(!caseData) return; + + const odds = caseData?.goldProfit !== undefined ? calculateGoldOdds(caseData.goldProfit) : `${caseData?.odds}%`; + const isJoker = caseData?.name?.endsWith(' JOKER') || false; + const cardEl = $(thisElement)?.find(eventCase ? 'div[data-testid="case-card-price-btn"]' : 'div.absolute.right-3.rounded.bg-navy-900.px-3.text-xs.font-semibold.text-gold-500')?.eq(0); + if (init) $(cardEl).after($(document?.createElement('div')) ?.addClass(eventCase ? 'cardOdds absolute right-3 top-3 rounded bg-navy-900 px-3 py-1.5 text-xs font-semibold text-white' : 'cardOdds absolute right-3 rounded bg-navy-900 px-3 py-1.5 text-xs font-semibold text-gold-500') ?.css({ 'margin-top': eventCase ? '35px' : '45px', 'background': isJoker ? 'rgb(129 72 234)' : 'rgb(23 23 28)' }) - ?.text($(thisElement)?.attr('case-orginal') ? odds : (thisCase[0]?.lang || odds)) + ?.text($(thisElement)?.attr('case-orginal') ? odds : (caseData?.lang || odds)) ); - $(thisElement)?.find('.cardOdds')?.text($(thisElement)?.attr('case-orginal') ? odds : (thisCase[0]?.lang || odds)) + $(thisElement)?.find('.cardOdds')?.text($(thisElement)?.attr('case-orginal') ? odds : (caseData?.lang || odds)) $(thisElement)?.find('.cardOdds')?.css({ 'background': isJoker ? 'rgb(129 72 234)' : 'rgb(23 23 28)' }) $(thisElement)?.find('div[data-testid=case-card-badge-btn] p') @@ -121,12 +111,7 @@ const createCaseOdds = async(config, currentRate, currency, cases, thisElement, $(thisElement)?.find('div.css-hmmmg1') ?.css({ 'background': isJoker ? 'rgb(129 72 234)' : 'rgb(23 23 28)' }) - const formattedPrice = new Intl.NumberFormat('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(thisCase[0]?.price_USD * currentRate); - - const priceText = `${formattedPrice} ${currency}`; + const priceText = formatCurrency(caseData?.price_USD * currentRate, currency); if (isJoker || !init) $(thisElement)?.find('[data-testid="case-card-price-btn"]') ?.text(priceText); @@ -138,12 +123,7 @@ const createYTcases = async(currentRate, currency, cases) => { if(!YTcases || !YTcases?.length) return; YTcases?.forEach(el => { - const formattedPrice = new Intl.NumberFormat('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(el?.price_USD * currentRate); - - const priceText = `${formattedPrice} ${currency}`; + const priceText = formatCurrency(el?.price_USD * currentRate, currency); $('section#youtubers-cases div.grid.gap-6')?.eq(0)?.append($(document.createElement('div')) ?.addClass("keydrop-plus-ytcases group relative transition-all duration-200 will-change-transform hover:-translate-y-0.5 aspect-[270/375] col-span-2") ?.html(`
${priceText}
${el?.odds}%

${el?.name}

`) diff --git a/js/dailyCaseTimer.js b/js/dailyCaseTimer.js index 55d6ac9..535471c 100644 --- a/js/dailyCaseTimer.js +++ b/js/dailyCaseTimer.js @@ -61,7 +61,7 @@ const createSkinsValueDiv = async() => { const fetch = await fetchUrl("GET", "https://key-drop.com/en/panel/profil/eq_value"); if(!fetch) return; - const data = JSON.parse(fetch); + const data = fetch; const skinsValue = `${(data?.fullPrice).toFixed(2).toString().replace('.',',')} ${data?.currency}`; $('div[data-testid="balance"]') diff --git a/js/giveawaysList.js b/js/giveawaysList.js index 0439311..63bea15 100644 --- a/js/giveawaysList.js +++ b/js/giveawaysList.js @@ -57,11 +57,13 @@ const createGiveawayListPanel = async() => { endDate: language?.autogiveaway_endDate, }; - $('#main-view div.min-h-screen.pb-16 div.container').eq(2) - .after($(document.createElement('div')) - .addClass('container giveaway-keydropPlus-info') - .html(`
Keydrop Plus

${panelText?.settings}

${panelText?.settings_p1}

${panelText?.settings_a1}

${panelText?.settings_p5}: PLN

${panelText?.settings_a5}

${panelText?.settings_p3}: N/A

${panelText?.settings_a3}

${panelText?.settings_p4}: N/A

${panelText?.settings_a4}${panelText?.settings_desc}

${panelText?.history}

${panelText?.id}${panelText?.salary}${panelText?.joined2}${panelText?.endDate}
`) - ) //

${panelText?.settings_p2}: 0

${panelText?.settings_a2} + $('#main-view div.min-h-screen.pb-16 div.container').eq(2) + .after($(document.createElement('div')) + .addClass('container giveaway-keydropPlus-info') + .html(`
Keydrop Plus

${panelText?.settings}

${panelText?.settings_p1}

${panelText?.settings_a1}

${panelText?.settings_p5}: PLN

${panelText?.settings_a5}

${panelText?.settings_p3}: N/A

${panelText?.settings_a3}

${panelText?.settings_p4}: N/A

${panelText?.settings_a4}${panelText?.settings_desc}

${panelText?.history}

${panelText?.id}${panelText?.salary}${panelText?.joined2}${panelText?.endDate}
`) + ) //

${panelText?.settings_p2}: 0

${panelText?.settings_a2} + + $('#giveawayPagesWrapper').html(`

${panelText?.settings_p6}:

${panelText?.settings_a6}`); if(autoGiveawayConfig?.winNotification) $('#notificationSwitch').prop('checked', true); @@ -74,13 +76,15 @@ const createGiveawayListPanel = async() => { const autoGiveawayConfigData = await getAutoGiveawayConfigData(); if(!autoGiveawayConfigData) return; autoGiveawayConfigData.winNotification = e?.target?.checked; - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); }); - if(autoGiveawayConfig?.minPrice) - $('#giveawayMinPrice').val(autoGiveawayConfig?.minPrice); + if(autoGiveawayConfig?.minPrice) + $('#giveawayMinPrice').val(autoGiveawayConfig?.minPrice); + if(autoGiveawayConfig?.pagesToCheck) + $('#giveawayPages').val(autoGiveawayConfig?.pagesToCheck); - $('#autoGiveawayButton').on('click', async() => { + $('#autoGiveawayButton').on('click', async() => { const autoGiveawayConfigData = await getAutoGiveawayConfigData(); const checked = autoGiveawayConfigData?.active; $('#autoGiveawayButton').removeClass(checked ? 'button-primary' : 'button-light-green'); @@ -88,11 +92,12 @@ const createGiveawayListPanel = async() => { $('#autoGiveawayButton').text(checked ? panelText?.start : panelText?.disable); $('#giveawaySearch').css('display', checked ? 'none' : 'block'); $('#main-view div.grid-stack.relative.grid.overflow-hidden').eq(4).css('display', checked ? 'block' : 'none') - autoGiveawayConfigData.active = !autoGiveawayConfigData?.active; - autoGiveawayConfigData.minPrice = $('#giveawayMinPrice')?.val(); - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; - createToast('info', checked ? 'autogiveaway_deactivate' : 'autogiveaway_active'); - }); + autoGiveawayConfigData.active = !autoGiveawayConfigData?.active; + autoGiveawayConfigData.minPrice = $('#giveawayMinPrice')?.val(); + autoGiveawayConfigData.pagesToCheck = $('#giveawayPages')?.val(); + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); + createToast('info', checked ? 'autogiveaway_deactivate' : 'autogiveaway_active'); + }); refreshGiveawaysPanel(panelText); }; @@ -101,7 +106,7 @@ const refreshGiveawaysPanel = async(panelText) => { if(!config?.active) return; const index = await getIndexData(); - let giveawaysHistory = await getStorageData('local', 'giveawaysHistory'); + let giveawaysHistory = await getStorageData('local', 'giveawaysHistory', []); const userSkins = await getUserSkinsData(config?.token); const giveawayWinnersTab = userSkins?.length !== 0 ? userSkins?.filter(el => el?.sourceType == 'giveaway') : []; @@ -122,7 +127,7 @@ const refreshGiveawaysPanel = async(panelText) => { if(giveawaysHistory?.length >= 100) { giveawaysHistory = giveawaysHistory?.slice(1, 100); - try { chrome.storage.local.set({ giveawaysHistory: giveawaysHistory }); } catch(e) {}; + setStorageData('local', { giveawaysHistory: giveawaysHistory }); } // let joinsCount = 20; @@ -161,7 +166,7 @@ const refreshGiveawaysPanel = async(panelText) => { $('#autoGiveawayButton').text(panelText?.start); $('#giveawaySearch').css('display', 'none'); $('#main-view div.grid-stack.relative.grid.overflow-hidden').eq(4).css('display', 'block'); - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfig }); }*/ if(autoGiveawayConfig?.active) { diff --git a/js/joinCaseBattle.js b/js/joinCaseBattle.js index 952658f..51b564e 100644 --- a/js/joinCaseBattle.js +++ b/js/joinCaseBattle.js @@ -66,7 +66,13 @@ const createAutoCaseBattlePanel = async() => { let lastCaseBattleId; const findFreeCaseBattle = async(fastCaseBattleConfig) => { - const fetch = await fetchUrl('GET', 'https://key-drop.app/v2/battle?type=active&page=0&priceFrom=0&priceTo=undefined&searchText=&sort=latest&roundsCount=all', null, true); + // Request all active battles without limiting price or round count + const fetch = await fetchUrl( + 'GET', + 'https://key-drop.app/v2/battle?type=active&page=0&priceFrom=0&searchText=&sort=latest', + null, + true + ); if(!fetch || !fetch?.data) return 'end'; let filtered = await fetch?.data?.filter(el => el?.status == 'new' && el?.roundsCount >= fastCaseBattleConfig?.minCaseCount && el?.users?.length == 0 && el?.isFreeBattle == true && (fastCaseBattleConfig?.casesName?.includes(el?.cases[0]?.name) || fastCaseBattleConfig?.casesName?.includes(el?.cases[1]?.name))); @@ -155,7 +161,7 @@ function autoJoinCaseBattle() { return createToast('error', 'autoJoinFreeCaseBattle_noPlayers'); if(fastCaseBattleConfig?.casesName?.length <= 0) return createToast('error', 'autoJoinFreeCaseBattle_noCaseName'); - try { chrome.storage.sync.set({ fastCaseBattleConfig: fastCaseBattleConfig }) } catch(e) {}; + setStorageData('sync', { fastCaseBattleConfig: fastCaseBattleConfig }); fastCaseBattleData = fastCaseBattleConfig; autoJoinActive = !autoJoinActive; diff --git a/js/joinGiveaway.js b/js/joinGiveaway.js index e2ce43c..ee23474 100644 --- a/js/joinGiveaway.js +++ b/js/joinGiveaway.js @@ -1,5 +1,6 @@ let giveawayInterval = null; -const refreshGiveawayTime = 45 * 1000; +const refreshGiveawayTime = 45 * 1000; +const getRefreshDelay = () => refreshGiveawayTime + Math.floor(Math.random() * 10 * 1000); const giveawayStart = async(isFirst) => { const config = await getConfigData(); @@ -37,7 +38,7 @@ const runAutoGiveaway = async(language, port, currentRate, isFirst) => { //const waitingTime = (autoGiveawayConfig?.currentGiveaway?.deadlineTimestamp - new Date().getTime()) + Math.floor(Math.random() * 60000) + 60000; setTimeout(async() => { return runAutoGiveaway(language, port, currentRate); - }, refreshGiveawayTime);// waitingTime > 0 ? waitingTime : (15 * 60 * 1000)); + }, getRefreshDelay());// waitingTime > 0 ? waitingTime : (15 * 60 * 1000)); }; const getGiveawayData = async(language, gConfig, port, token) => { @@ -71,27 +72,32 @@ const getGiveawayData = async(language, gConfig, port, token) => { gConfig.currentGiveaway.haveIJoined = false; gConfig.currentGiveaway.captcha = false; gConfig.currentGiveaway.maxPrice = null; - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); const giveawaysHistory = await getStorageData('local', 'giveawaysHistory') || []; giveawaysHistory.push(giveaway); - try { chrome.storage.local.set({ giveawaysHistory: giveawaysHistory }); } catch(e) {}; + setStorageData('local', { giveawaysHistory: giveawaysHistory }); return gConfig; }; const findNewGiveaway = async(gConfig, port, token) => { - const fetch = JSON.parse(JSON.stringify(await fetchUrl('GET', `https://wss-${port || 2061}.key-drop.com/v1/giveaway//list?type=active&page=0&perPage=5&status=active&sort=latest`, token))); - if(!fetch || !fetch?.data) return createToast('error', 'error_fetch'); + const pages = gConfig?.pagesToCheck || 1; + let amateurGiveaways = null; + + for(let page = 0; page < pages && !amateurGiveaways; page++) { + const fetch = JSON.parse(JSON.stringify(await fetchUrl('GET', `https://wss-${port || 2061}.key-drop.com/v1/giveaway//list?type=active&page=${page}&perPage=5&status=active&sort=latest`, token))); + if(!fetch || !fetch?.data) continue; + amateurGiveaways = fetch?.data?.find(el => el?.frequency == 'amateur'); + } - const amateurGiveaways = fetch?.data?.find(el => el?.frequency == 'amateur'); if(!amateurGiveaways) return createToast('error', 'error_fetch'); gConfig.currentGiveaway.id = amateurGiveaways?.id; gConfig.currentGiveaway.deadlineTimestamp = amateurGiveaways?.deadlineTimestamp; gConfig.currentGiveaway.haveIJoined = amateurGiveaways?.haveIJoined; gConfig.currentGiveaway.maxPrice = amateurGiveaways?.prizes[0]?.price; - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); return gConfig; }; @@ -111,7 +117,7 @@ const joinGiveaway = async(language, gConfig, token) => { } else createToast('error', null, idText, giveawayUrl, `${language?.autogiveaway_error} ${fetch?.message}`); - try { chrome.storage.sync.set({ autoGiveawayConfig: gConfig }); } catch(e) {}; + setStorageData('sync', { autoGiveawayConfig: gConfig }); return gConfig; }; diff --git a/js/main.js b/js/main.js index f6b92e7..a17a393 100644 --- a/js/main.js +++ b/js/main.js @@ -1,3 +1,4 @@ +/* global fetchUrl, getStorageData, setStorageData, clearStorageData */ const active = true; const version = "F2.11"; const toastCooldown = 4 * 1000 @@ -12,40 +13,13 @@ $('body').append($(document.createElement('div')) .css({ position: 'fixed', right: 0, 'margin-right': '10px', 'margin-bottom': '11px', bottom: 0, 'z-index': 999 }) ); -const fetchUrl = async(type, url, token, noTime, data) => { - try { - const result = await $.ajax({ - type: type, - url: `${url}${noTime ? '' : `?t=${new Date().getTime()}`}`, - data: data ? JSON.stringify(data) : '', - beforeSend: async (xhr) => { - if(token) - xhr.setRequestHeader('authorization', `Bearer ${token}`); - }, - success: function (response, textStatus, jqXHR) { - if(!response) - return createToast('error', 'error_fetch'); - return JSON.parse(JSON.stringify(response)) || undefined; - }, - error: function(error) { - return; - } - }); - return result; - } catch(e) { if(e?.status == 403) return window?.location?.reload(); }; -}; - -const getStorageData = async(type, name) => { - try { - const storageData = - (type === 'local' || type === 0) ? await chrome.storage.local.get([name]).then((result) => { return result[name]; }) - : await chrome.storage.sync.get([name]).then((result) => { return result[name] }); - return storageData; - } catch(e) { - return;// console.log(e); - }; -} +/** + * Retrieve user index data from storage or remote endpoint. + * Cached values expire after a predefined period. + * + * @returns {Promise} Index data object + */ const getIndexData = async() => { const storageData = await getStorageData(1, 'index'); if(storageData?.expires >= new Date().getTime()) return storageData; @@ -59,10 +33,15 @@ const getIndexData = async() => { currency: fetch?.currency, currencyRates: fetch?.rates || [{id: 'EUR', rate: 1}, {id: 'PLN', rate: 5}, {id: 'USD', rate: 1}, {id: 'UAH', rate: 36.5}, {id: 'BRL', rate: 5.13}, {id: 'ARS', rate: 175}, {id: 'GBP', rate: 0.89}, {id: 'CZK', rate: 25.5}] }; - try { chrome.storage.sync.set({ index: indexData }); } catch(e) {}; + try { await setStorageData('sync', { index: indexData }); } catch(e) {}; return indexData; }; +/** + * Load extension configuration and validate token expiration. + * + * @returns {Promise} Configuration data + */ const getConfigData = async() => { const storageData = await getStorageData(1, 'config'); const configData = { @@ -89,12 +68,18 @@ const getConfigData = async() => { if(refreshedConfigData?.tokenExp && refreshedConfigData?.tokenExp > (new Date().getTime() + tokenExpiresTime)) { refreshedConfigData.token = null; refreshedConfigData.tokenExp = null; - try { chrome.storage.sync.set({ config: refreshedConfigData }); } catch(e) {}; + try { await setStorageData('sync', { config: refreshedConfigData }); } catch(e) {}; createToast('warning', 'warning_dateManipulated'); } return refreshedConfigData; }; +/** + * Refresh authorization token when expired and persist it. + * + * @param {Object} config Current configuration + * @returns {Promise} Updated configuration + */ const checkToken = async(config) => { const timestamp = new Date().getTime(); if(!config?.token || timestamp >= config?.tokenExp) { @@ -103,13 +88,13 @@ const checkToken = async(config) => { config.token = fetch; config.tokenExp = timestamp + tokenExpiresTime; } - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + try { await setStorageData('sync', { config: config }); } catch(e) {}; return config; }; const getServerData = async() => { - const fetch = JSON.parse(await fetchUrl('GET', `${githubUrl}/serverData.json`)); + const fetch = await fetchUrl('GET', `${githubUrl}/serverData.json`); if(!fetch || !fetch?.current_versions) return; return fetch; }; @@ -127,9 +112,8 @@ const getLanguageData = async(lang) => { } const fetch = await fetchUrl('GET', `${githubUrl}/lang/${lang}.json`); - if(!fetch || fetch?.length <= 0) return; - const json = JSON.parse(fetch); - return json; + if(!fetch) return; + return fetch; }; const getCookieValue = (cookieName) => { @@ -142,21 +126,37 @@ const getCookieValue = (cookieName) => { return null; } +/** + * Determine the user's currency either from cookie or remote endpoint. + * Falls back to USD when unavailable. + * + * @returns {Promise} ISO currency code + */ const getCurrency = async() => { let currency = getCookieValue('currency'); - if (currency == null) { - fetch = await fetchUrl('GET', 'https://key-drop.com/en/balance?skinsValue=true'); - currency = JSON.parse(fetch)?.currency; + if (!currency) { + const balanceData = await fetchUrl('GET', 'https://key-drop.com/en/balance?skinsValue=true'); + currency = balanceData?.currency; } return currency || 'USD'; -} +}; +/** + * Retrieve auto-giveaway configuration or initialize defaults. + * + * @returns {Promise} Auto-giveaway configuration + */ const getAutoGiveawayConfigData = async() => { const storageData = await getStorageData(1, 'autoGiveawayConfig'); - if(storageData) return storageData; + if(storageData) { + if(!storageData?.pagesToCheck) + storageData.pagesToCheck = 1; + return storageData; + } const autoGiveawayConfigData = { active: false, winNotification: false, + pagesToCheck: 1, currentGiveaway: { id: null, deadlineTimestamp: null, @@ -164,10 +164,16 @@ const getAutoGiveawayConfigData = async() => { captcha: false }, } - try { chrome.storage.sync.set({ autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; + try { await setStorageData('sync', { autoGiveawayConfig: autoGiveawayConfigData }); } catch(e) {}; return autoGiveawayConfigData; }; +/** + * Fetch paginated list of user skins. + * + * @param {string} token Authorization token + * @returns {Promise} Array of skin data + */ const getUserSkinsData = async(token) => { let currentPage = 1; let totalUserSkins = 1; @@ -175,7 +181,7 @@ const getUserSkinsData = async(token) => { const totalMaxSkins = 999; do { - const fetch = JSON.parse(await fetchUrl('GET', `https://key-drop.com/en/panel/profil/my_winner_list?type=all&sort=newest&state=all&per_page=${totalMaxSkins}¤t_page=${currentPage}?t=${new Date().getTime()}`, token)); + const fetch = await fetchUrl('GET', `https://key-drop.com/en/panel/profil/my_winner_list?type=all&sort=newest&state=all&per_page=${totalMaxSkins}¤t_page=${currentPage}`, token); if(!fetch || !fetch?.total || fetch?.data?.length <= 0) return; totalUserSkins = fetch?.total || 1; if(currentPage == 1) userSkinsArray = fetch?.data; @@ -267,21 +273,35 @@ const createNotifications = async(text, url, newTab) => { }); }; -const waitForElm = async(selector) => { +/** + * Wait for a DOM element matching the selector to appear. + * Resolves with `null` if the element does not appear within the timeout. + * + * @param {string} selector CSS selector to watch for + * @param {number} [timeout=0] Maximum time to wait in milliseconds; 0 disables timeout + * @returns {Promise} Found element or null on timeout + */ +const waitForElm = async(selector, timeout = 0) => { return new Promise(resolve => { - if(document.querySelector(selector)) { - return resolve(document.querySelector(selector)); - }; - const observer = new MutationObserver(mutations => { - if(document.querySelector(selector)) { - resolve(document.querySelector(selector)); + const initial = document.querySelector(selector); + if(initial) return resolve(initial); + + const observer = new MutationObserver(() => { + const element = document.querySelector(selector); + if(element) { observer.disconnect(); + resolve(element); } }); - observer.observe(document.body, { - childList: true, - subtree: true - }); + + observer.observe(document.body, { childList: true, subtree: true }); + + if(timeout > 0) { + setTimeout(() => { + observer.disconnect(); + resolve(null); + }, timeout); + } }); }; @@ -359,7 +379,7 @@ const verifyUser = async() => { const configData = await getConfigData(); configData.active = true; - chrome.storage.sync.set({ config: configData }); + setStorageData('sync', { config: configData }); return; }; verifyUser(); diff --git a/js/settingsPanel.js b/js/settingsPanel.js index 2666db6..7a7330f 100644 --- a/js/settingsPanel.js +++ b/js/settingsPanel.js @@ -5,103 +5,78 @@ $( document ).ready(async() => { const server = await getServerData(); if(!server) return; await createSettingsPanel(config, language, server); + const attachToggle = (key, selector, { onInit, onChange } = {}) => { + if(config?.[key]) $(selector)?.prop('checked', true); + if(onInit) onInit(!!config?.[key]); + $(selector)?.on('change', function(e) { + const checked = e?.target?.checked; + config[key] = checked; + setStorageData('sync', { config: config }); + if(onChange) onChange(checked); + }); + }; if(window?.location?.href?.includes('/#keydrop_plus')) $('div#keydrop-plus-modal')?.addClass('is-open'); $('#keydrop-plus-modal').click(function(e) { if(e?.target?.id == 'close-keydrop-plus-modal' || e?.target?.id == "keydrop-plus-modal") - $('#keydrop-plus-modal') - .removeClass('is-open'); - }); - - if(config?.toastSoundEnable_error) - $('#toastSoundEnable_error')?.prop('checked', true); - $('#toastSoundEnable_error')?.on('change', function(e) { - config.toastSoundEnable_error = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); - - if(config?.toastSoundEnable_info) - $('#toastSoundEnable_info')?.prop('checked', true); - $('#toastSoundEnable_info')?.on('change', function(e) { - config.toastSoundEnable_info = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); - - if(config?.toastSoundEnable_success) - $('#toastSoundEnable_success')?.prop('checked', true); - $('#toastSoundEnable_success')?.on('change', function(e) { - config.toastSoundEnable_success = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + $('#keydrop-plus-modal').removeClass('is-open'); }); - if(config?.toastSoundEnable_warning) - $('#toastSoundEnable_warning')?.prop('checked', true); - $('#toastSoundEnable_warning')?.on('change', function(e) { - config.toastSoundEnable_warning = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + ['error','info','success','warning'].forEach(type => { + attachToggle(`toastSoundEnable_${type}`, `#toastSoundEnable_${type}`); }); - if(config?.toastAutoHide) - $('#hideToast')?.prop('checked', true); - $('#hideToast')?.on('change', function(e) { - config.toastAutoHide = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - }); + attachToggle('toastAutoHide', '#hideToast'); - if(config?.showAllYoutuberCases) - $('#showAllYoutuberCases')?.prop('checked', true); - $('#showAllYoutuberCases')?.on('change', function(e) { - $('.keydrop-plus-ytcases').css('display', e?.target?.checked ? 'block' : 'none'); - $('[case-orginal="true"').css('display', e?.target?.checked ? 'none' : 'block'); - config.showAllYoutuberCases = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; + attachToggle('showAllYoutuberCases', '#showAllYoutuberCases', { + onChange: (checked) => { + $('.keydrop-plus-ytcases').css('display', checked ? 'block' : 'none'); + $('[case-orginal="true"]').css('display', checked ? 'none' : 'block'); + } }); - if(config?.hideLiveDrop) { - $('#hideLiveDrop')?.prop('checked', true); - waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => { - if(config?.hideLiveDrop) - $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none'); - }); - } - $('#hideLiveDrop')?.on('change', function(e) { - config.hideLiveDrop = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'flex'); + attachToggle('hideLiveDrop', '#hideLiveDrop', { + onInit: (checked) => { + if(checked) + waitForElm('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row').then(() => { + $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', 'none'); + }); + }, + onChange: (checked) => { + $('div.flex.flex-col.overflow-hidden.bg-navy-900.lg\\:flex-row')?.eq(0)?.css('display', checked ? 'none' : 'flex'); + } }); - if(config?.hideCaseBattle) { - $('#hideCaseBattle')?.prop('checked', true); - waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => { - if(!config?.hideCaseBattle) - return; - $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none'); - $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px'); - }); - } - $('#hideCaseBattle')?.on('change', function(e) { - config.hideCaseBattle = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', e?.target?.checked ? 'none' : 'block'); - $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', e?.target?.checked ? '50px' : '0px'); + attachToggle('hideCaseBattle', '#hideCaseBattle', { + onInit: (checked) => { + waitForElm('[data-testid="single-bttl-rounds-counter"]').then(() => { + if(checked) { + $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', 'none'); + $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', '50px'); + } + }); + }, + onChange: (checked) => { + $('div#caseList-root div.container.mb-8')?.eq(0)?.css('display', checked ? 'none' : 'block'); + $('div#caseList-root div.mx-auto.max-w-screen-2xl.2xl\\:px-5')?.eq(0)?.css('margin-top', checked ? '50px' : '0px'); + } }); - if(config?.hideFavourite) { - $('#hideFavourite')?.prop('checked', true); - $('section#favorite')?.css('display', 'none'); - } - $('#hideFavourite')?.on('change', function(e) { - config.hideFavourite = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); } catch(e) {}; - $('section#favorite')?.css('display', e?.target?.checked ? 'none' : 'block'); + attachToggle('hideFavourite', '#hideFavourite', { + onInit: (checked) => { + if(checked) $('section#favorite')?.css('display', 'none'); + }, + onChange: (checked) => { + $('section#favorite')?.css('display', checked ? 'none' : 'block'); + } }); $('#keydrop-plus-remove-data')?.on('click', function(e) { - try { chrome.storage.sync.clear(); } catch(e) {}; + clearStorageData('sync'); setTimeout(async() => { - try { chrome.storage.local.clear(); } catch(e) {}; + clearStorageData('local'); window?.location?.reload(); }, 200); }); @@ -113,20 +88,23 @@ $( document ).ready(async() => { const config = await getConfigData(); const casesFetch = await fetchUrl('GET', `${githubUrl}/cases.json`) if(!casesFetch || !config) return; - const cases = JSON.parse(`{"cases": ${casesFetch}}`)?.cases; + const cases = Array.isArray(casesFetch) ? casesFetch : casesFetch?.cases; if(!cases?.length) return; config.showJokerOdds = e?.target?.checked; - try { chrome.storage.sync.set({ config: config }); refreshOdds(config, cases); } catch(e) {}; + setStorageData('sync', { config: config }); + refreshOdds(config, cases); }); - $(`.keydorp-plus-change-language[data-lang="${config?.lang}"]`) - ?.css('filter', 'opacity(0.8)'); + const langSelector = `.keydorp-plus-change-language[data-lang="${config?.lang}"]`; + $(langSelector).addClass('active'); $('.keydorp-plus-change-language')?.click(function() { const lnagData = $(this)?.attr('data-lang'); config.lang = lnagData; - try{ chrome.storage.sync.set({ config: config }) } catch(e) {}; + setStorageData('sync', { config: config }); + $('.keydorp-plus-change-language').removeClass('active'); + $(this).addClass('active'); window?.location?.reload(); }); }); @@ -169,7 +147,7 @@ const createSettingsPanel = async(config, language, server) => { server?.languages?.forEach(el => { $("#keydrop-plus-remove-data").before($(document.createElement('div')) .css({ display: "inline-table", width: "65px" }) - .html(`

${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}

`) + .html(`

${el?.langBy != null ? `${languageText?.by} ${el?.langBy}` : ""}

`) ); }); }; \ No newline at end of file diff --git a/js/skinChanger.js b/js/skinChanger.js index 5c79cde..20319fd 100644 --- a/js/skinChanger.js +++ b/js/skinChanger.js @@ -209,7 +209,7 @@ const createMenu = async(language) => { try { const config = await getConfigData(); config.skinportPrice = e?.target?.checked; - await chrome.storage.sync.set({ config: config }); + await setStorageData('sync', { config: config }); refreshPrices(); } catch(e) {}; }); @@ -225,7 +225,7 @@ const createMenu = async(language) => { try { const config = await getConfigData(); config.steamPrice = e?.target?.checked; - await chrome.storage.sync.set({ config: config }); + await setStorageData('sync', { config: config }); refreshPrices(); } catch(e) {}; }); diff --git a/js/ticketInfo.js b/js/ticketInfo.js index d82b0be..484f307 100644 --- a/js/ticketInfo.js +++ b/js/ticketInfo.js @@ -9,7 +9,7 @@ $( document ).ready(async() => { const createTicketsInfo = async() => { const fetch = await fetchUrl('GET', 'https://key-drop.com/en/balance?battleTickets=1'); - const data = JSON.parse(fetch); + const data = fetch; const tickets = data?.caseBattleTickets; $('div a[href="#gold-area"]').after($(document.createElement('a')) diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000..cf1f4bd --- /dev/null +++ b/js/utils.js @@ -0,0 +1,133 @@ +/* eslint no-unused-vars: "off" */ +/* global chrome */ +/* exported fetchUrl, getStorageData, setStorageData, clearStorageData, formatCurrency */ +/** + * General utility helpers for Keydrop+ extension. + * Includes network and storage helpers reused across modules. + */ + +/** Default timeout for network requests in milliseconds. */ +const defaultFetchTimeout = 15 * 1000; + +/** Simple in-memory cache for GET requests. */ +const fetchCache = new Map(); + +/** + * Perform a network request with optional authorization and body data. + * Automatically appends a timestamp to bust caches unless `noTime` is true. + * + * @param {string} type HTTP method + * @param {string} url Target URL + * @param {string|false} token Optional bearer token + * @param {boolean} noTime Skip timestamp parameter + * @param {Object} [data] JSON body payload + * @param {{timeout?:number, headers?:Object, cache?:number}} [options] + * Additional options including request timeout and cache duration + * (in ms) for GET requests. + * @returns {Promise<*>} Parsed JSON/text response or null on error + */ +const fetchUrl = async (type, url, token, noTime, data, options = {}) => { + const { timeout = defaultFetchTimeout, headers = {}, cache = 0 } = options; + const cacheKey = `${type}:${url}:${JSON.stringify(data)}`; + if (cache > 0 && type === 'GET') { + const cached = fetchCache.get(cacheKey); + if (cached && (Date.now() - cached.time) < cache) { + return cached.value; + } + } + try { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeout); + const requestUrl = new URL(url); + if (!noTime) requestUrl.searchParams.set('t', Date.now()); + const response = await fetch(requestUrl.toString(), { + method: type, + headers: { + ...(data ? { 'Content-Type': 'application/json' } : {}), + ...(token ? { authorization: `Bearer ${token}` } : {}), + ...headers + }, + body: data ? JSON.stringify(data) : undefined, + signal: controller.signal + }); + clearTimeout(timer); + if (response.status === 403) { + return window?.location?.reload(); + } + if (!response.ok) return null; + const contentType = response.headers.get('content-type') || ''; + const value = contentType.includes('application/json') + ? await response.json() + : await response.text(); + if (cache > 0 && type === 'GET') { + fetchCache.set(cacheKey, { time: Date.now(), value }); + } + return value; + } catch (e) { + return null; + } +}; + +/** + * Retrieve a value from browser storage. + * + * @param {'local'|'sync'|0|1} type Storage type + * @param {string} name Key name + * @param {*} [defaultValue] Value to return if key does not exist + * @returns {Promise<*>} Stored value or defaultValue + */ +const getStorageData = async (type, name, defaultValue) => { + try { + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + const result = await storage.get([name]); + return result[name] ?? defaultValue; + } catch (e) { + return defaultValue; + } +}; + +/** + * Save data to browser storage. + * + * @param {'local'|'sync'|0|1} type Storage type + * @param {Object} data Data to store + * @returns {Promise} True on success + */ +const setStorageData = async (type, data) => { + try { + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + await storage.set(data); + return true; + } catch (e) { + return false; + } +}; + +/** + * Clear all data from a storage area. + * + * @param {'local'|'sync'|0|1} type Storage type + * @returns {Promise} True on success + */ +const clearStorageData = async (type) => { + try { + const storage = (type === 'local' || type === 0) ? chrome.storage.local : chrome.storage.sync; + await storage.clear(); + return true; + } catch (e) { + return false; + } +}; + +/** + * Format a numeric value as a currency string. + * + * @param {number} value Numeric value to format + * @param {string} currency ISO currency code + * @param {string} [locale='en-US'] Locale for formatting + * @returns {string} Formatted currency string + */ +const formatCurrency = (value, currency, locale = 'en-US') => { + return `${new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value)} ${currency}`; +}; + diff --git a/js/websites/skinport.js b/js/websites/skinport.js index c3eb3c8..88af2b6 100644 --- a/js/websites/skinport.js +++ b/js/websites/skinport.js @@ -42,7 +42,7 @@ const getSkins = async() => { marketJSON.currency = currency; marketJSON.updateTime = `${new Date().getTime()}`; - try { chrome.storage.local.set({skinportMarketJSON: marketJSON }); } catch(e) {}; + setStorageData('local', {skinportMarketJSON: marketJSON }); setTimeout(function() { try { open(`https://key-drop.com/skin-changer`, '_self'); diff --git a/js/websites/steam.js b/js/websites/steam.js index 8b15e46..bba81d2 100644 --- a/js/websites/steam.js +++ b/js/websites/steam.js @@ -57,7 +57,7 @@ const loadSteamSkins = (langText) => { loadSteamSkins(langText); } else { marketJSON.updateTime = `${new Date().getTime()}`; - try { chrome.storage.local.set({steamMarketJSON: marketJSON}); } catch(e) {}; + setStorageData('local', {steamMarketJSON: marketJSON}); setTimeout(() => { try { open(`https://key-drop.com/skin-changer`, '_self'); diff --git a/manifest.json b/manifest.json index 132ee21..615fa1a 100644 --- a/manifest.json +++ b/manifest.json @@ -22,6 +22,7 @@ "js/jquery/jquery-3.6.1.min.js", "js/crypto/crypto-js.js", "js/caseOdds.js", + "js/utils.js", "js/main.js", "js/joinGiveaway.js", "js/dailyCaseTimer.js", @@ -103,6 +104,7 @@ "js": [ "js/jquery/jquery-3.6.1.min.js", "js/crypto/crypto-js.js", + "js/utils.js", "js/main.js", "js/websites/skinport.js" ], @@ -137,6 +139,7 @@ "js": [ "js/jquery/jquery-3.6.1.min.js", "js/crypto/crypto-js.js", + "js/utils.js", "js/main.js", "js/websites/steam.js" ], diff --git a/package-lock.json b/package-lock.json index 81353aa..b743dbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,1363 @@ { + "name": "keydropplus", + "version": "2.11.0", + "lockfileVersion": 3, "requires": true, - "lockfileVersion": 1, - "dependencies": { - "crypto-js": { + "packages": { + "": { + "name": "keydropplus", + "version": "2.11.0", + "license": "MIT", + "dependencies": { + "crypto-js": "^4.1.1" + }, + "devDependencies": { + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "prettier": "^3.2.5" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json new file mode 100644 index 0000000..9e25b65 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "keydropplus", + "version": "2.11.0", + "description": "Unofficial extension for keydrop.com that adds helpful features and improvements.", + "main": "js/main.js", + "scripts": { + "lint": "eslint js/main.js js/utils.js", + "format": "prettier --check README.md" + }, + "dependencies": { + "crypto-js": "^4.1.1" + }, + "devDependencies": { + "eslint": "^8.57.0", + "prettier": "^3.2.5", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3" + }, + "license": "MIT" +}