feat: enable webextension builds

Currently only supports Chrome due to no `chrome` -> `browser` polyfill
This commit is contained in:
xenticore
2025-05-01 15:27:14 -04:00
parent d02bd7ac9d
commit 95ce637892
15 changed files with 281 additions and 53 deletions

View File

@@ -0,0 +1,111 @@
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryExchangeRates") {
const url = "https://open.er-api.com/v6/latest/USD";
fetch(url)
.then(response => {
console.log(response)
return response.json()
})
.then(json => {
sendResponse(json)
})
.catch(error => {
console.error("Failed to get exchange rates", error);
})
return true;
}
})
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "querySchema") {
const url = "https://raw.githubusercontent.com/danocmx/node-tf2-static-schema/master/static/items.json";
fetch(url)
.then(response => response.json())
.then(json => sendResponse(json))
.catch(error => {
console.error("Failed to get schema", error);
})
return true;
}
}
);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "getPricesTFToken") {
fetch('https://api2.prices.tf/auth/access', {
method: 'post',
headers: new Headers({
'Accept': 'application/json'
})
})
.then(response => response.json())
.then(json => sendResponse(json['accessToken']))
.catch(error => {
console.error("Failed to get access token", error);
})
return true;
}
}
)
class PricesResponse {
keys: number
metal: number
}
async function priceUsingPricesTF(token: string, sku: string, retries: number = 3): Promise<PricesResponse> {
const url = `https://api2.prices.tf/prices/${encodeURIComponent(sku)}`;
const response = await fetch(url, {
method: 'get',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${token}`,
}
})
if (response.status === 404 && sku.includes(';') && !sku.includes(';uncraftable')) {
const quality: number = parseInt(sku.split(';')[1], 10);
if(quality === 6) {
// Try uncraftable variant if unique weapon
return priceUsingPricesTF(token, sku + ';uncraftable');
}
}
if(response.status === 503) {
// Happens if we send too many requests in a short period of time
// Retry after a few seconds
if(retries >= 0) {
console.log(`Cloudflare rate limit exceeded, trying again after 1 second, ${retries} retries left`)
await new Promise(resolve => setTimeout(resolve, 1000));
return priceUsingPricesTF(token, sku, retries - 1);
} else {
throw new Error(`Cloudflare rate limit exceeded, stopping`)
}
}
const data = await response.json();
const prices = new PricesResponse();
prices.keys = data['sellKeys']
prices.metal = data['sellHalfScrap'] / 18.0;
return prices;
}
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "priceSKU") {
const sku: string = request.sku
const service: string = request.service
const token: string = request.token
switch (service) {
case "prices.tf": {
priceUsingPricesTF(token, sku).then((response) => {
sendResponse(JSON.stringify(response));
})
return true;
}
default:
return false;
}
}
}
);