diff --git a/.cursor/debug.log b/.cursor/debug.log index baef34e..a294f44 100644 --- a/.cursor/debug.log +++ b/.cursor/debug.log @@ -1,11 +1,54 @@ -{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":216,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":8,"cols":27,"cellSize":56},"timestamp":1768696693322,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"} -{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":27,"calculatedRows":8,"viewportSize":{"width":0,"height":0},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693324,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} -{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":216,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":8,"cols":27,"cellSize":56},"timestamp":1768696693330,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"} -{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":27,"calculatedRows":8,"viewportSize":{"width":0,"height":0},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693330,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} -{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":396,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":18,"cols":22,"cellSize":56},"timestamp":1768696693374,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"} -{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":22,"calculatedRows":18,"viewportSize":{"width":1070,"height":853},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693376,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} -{"location":"ebayParserService.js:341","message":"parseEbayAccount entry","data":{"url":"https://www.ebay.de/str/apecollection?_trksid=p4429486.m3561.l161210"},"timestamp":1768696699523,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"} -{"location":"ebayParserService.js:346","message":"parseEbayAccount: isExtensionAvailable result","data":{"extAvailable":false,"willTryExtension":false},"timestamp":1768696699525,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"} -{"location":"ebayParserService.js:94","message":"isExtensionAvailable check","data":{"hasFlag":false,"result":false},"timestamp":1768696699524,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"} -{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":408,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":17,"cols":24,"cellSize":56},"timestamp":1768696852148,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"} -{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1203,"containerHeight":840,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":24,"calculatedRows":17,"viewportSize":{"width":1203,"height":840},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696852149,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"productsService.js:116","message":"scanProductsForAccount: market derived","data":{"accountId":"696ccb2400395714987c","market":"DE","account_platform_market":"DE","account_url":"https://www.ebay.de/sch/i.html?item=397047173300&rt=nc&_trksid=p4429486.m3561.l161211&_ssn=miceusi"},"timestamp":1768741151411,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"} +{"location":"productsService.js:127","message":"scanProductsForAccount: currency derived","data":{"market":"DE","currency":"EUR","productsCollectionId":"products","databaseId":"eship-db","platformWillBeSetTo":"eBay"},"timestamp":1768741151411,"sessionId":"debug-session","runId":"post-fix","hypothesisId":"E"} +{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_1","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_1\",\"product_title\":\"Scanned Item 1\",\"product_price\":58.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-1\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151507,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"} +{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_1","created":0},"timestamp":1768741151644,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_2","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_2\",\"product_title\":\"Scanned Item 2\",\"product_price\":64,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-2\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151644,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"} +{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_2","created":1},"timestamp":1768741151700,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_3","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_3\",\"product_title\":\"Scanned Item 3\",\"product_price\":69.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-3\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151701,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"} +{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_3","created":2},"timestamp":1768741151751,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_4","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_4\",\"product_title\":\"Scanned Item 4\",\"product_price\":75,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-4\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151752,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"} +{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_4","created":3},"timestamp":1768741151800,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_5","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_5\",\"product_title\":\"Scanned Item 5\",\"product_price\":80.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-5\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151800,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"} +{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_5","created":4},"timestamp":1768741151844,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741538650,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741538651,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741538659,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741538659,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741538660,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"AccountsPage.jsx:193","message":"handleFormSubmit: parsedData before save","data":{"hasStats":true,"itemsSold":null,"accountSellsValue":null},"timestamp":1768741540654,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"accountsService.js:72","message":"createManagedAccount: payload before Appwrite","data":{"account_sells":null,"accountData_account_sells":null},"timestamp":1768741540655,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741552261,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741552262,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741552269,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741552269,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000uuvjdi","account_shop_name":"eBay Seller vjdi","account_sells":null}},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cdaa40028f011f5d0","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000uuvjdi","account_shop_name":"eBay Seller vjdi"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cdaa40028f011f5d0"},"timestamp":1768741552346,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/ihaveitmusic?_trksid=p4429486.m3561.l161211"},"timestamp":1768741553567,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741553568,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000h1nxit","account_shop_name":"eBay Seller nxit","account_sells":null}},"timestamp":1768741553575,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cbd07000703cf5437","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000h1nxit","account_shop_name":"eBay Seller nxit"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741553575,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cbd07000703cf5437"},"timestamp":1768741553651,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741571041,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741571042,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":1588,"stats":{"positiveRate":7,"feedbackCount":0,"itemsForSale":588,"itemsSold":1588}},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"goldbloom25","account_shop_name":"goldbloom25","account_sells":1588}},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cdaa40028f011f5d0","payload":{"account_platform_market":"DE","account_platform_account_id":"goldbloom25","account_shop_name":"goldbloom25","account_sells":1588},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cdaa40028f011f5d0"},"timestamp":1768741574001,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/sch/i.html?item=397047173300&rt=nc&_trksid=p4429486.m3561.l161211&_ssn=miceusi"},"timestamp":1768741581711,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741581712,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"timeout"},"timestamp":1768741596751,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_00002jm9ly","account_shop_name":"eBay Seller m9ly","account_sells":null}},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696ccb2400395714987c","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_00002jm9ly","account_shop_name":"eBay Seller m9ly"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696ccb2400395714987c"},"timestamp":1768741596841,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/ihaveitmusic?_trksid=p4429486.m3561.l161211"},"timestamp":1768741610165,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741610165,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":280535,"stats":{"positiveRate":5,"feedbackCount":0,"itemsForSale":535,"itemsSold":280535}},"timestamp":1768741616427,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"} +{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cbd07000703cf5437","payload":{"account_platform_market":"DE","account_platform_account_id":"ihaveitmusic","account_shop_name":"iHaveit","account_sells":280535},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1768741616428,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ihaveitmusic","account_shop_name":"iHaveit","account_sells":280535}},"timestamp":1768741616427,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} +{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cbd07000703cf5437"},"timestamp":1768741616513,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"} diff --git a/Extension/background.js b/Extension/background.js index 2cf43f0..a489f49 100644 --- a/Extension/background.js +++ b/Extension/background.js @@ -2,7 +2,9 @@ const STORAGE_KEY = "auth_jwt"; const BACKEND_URL = "http://localhost:5173"; // TODO: Backend URL konfigurieren const PARSE_TIMEOUT_MS = 15000; // 15 seconds +const SCAN_TIMEOUT_MS = 20000; // 20 seconds (seller listing pages can be slower) const activeParseRequests = new Map(); // Map +const activeScanRequests = new Map(); // Map // Messages from content script (der von der Web-App kommt) chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { @@ -57,6 +59,11 @@ chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => { handleParseRequest(msg.url, sendResponse); return true; // async } + + if (msg?.action === "SCAN_PRODUCTS" && msg.url && msg.accountId) { + handleScanProductsRequest(msg.url, msg.accountId, sendResponse); + return true; // async + } }); /** @@ -167,6 +174,114 @@ async function cleanupParseRequest(tabId, data, error) { } } +/** + * Handles eBay product scan request + * Creates a hidden tab, waits for load, sends parse message to content script + */ +async function handleScanProductsRequest(url, accountId, sendResponse) { + try { + // Validate URL + if (!url || typeof url !== 'string' || !url.toLowerCase().includes('ebay.')) { + sendResponse({ ok: false, error: "Invalid eBay URL" }); + return; + } + + // Create hidden tab + const tab = await chrome.tabs.create({ + url: url, + active: false + }); + + const tabId = tab.id; + + // Set up timeout + const timeoutId = setTimeout(() => { + cleanupScanRequest(tabId, null, { ok: false, error: "timeout" }); + }, SCAN_TIMEOUT_MS); + + // Store request info + activeScanRequests.set(tabId, { + timeout: timeoutId, + sendResponse: sendResponse + }); + + // Wait for tab to load, then send parse message + const checkTabLoaded = (updatedTabId, changeInfo, updatedTab) => { + if (updatedTabId !== tabId) return; + + // Tab is fully loaded + if (changeInfo.status === 'complete' && updatedTab.url) { + chrome.tabs.onUpdated.removeListener(checkTabLoaded); + + // Small delay to ensure DOM is ready + setTimeout(() => { + // Send parse message to content script + chrome.tabs.sendMessage(tabId, { action: "PARSE_PRODUCT_LIST" }) + .then(response => { + if (response && response.ok && response.data) { + handleScanComplete(tabId, response.data); + } else { + cleanupScanRequest(tabId, null, { ok: false, error: response?.error || "Parsing failed" }); + } + }) + .catch(err => { + console.error("Error sending parse message:", err); + cleanupScanRequest(tabId, null, { ok: false, error: "Content script error" }); + }); + }, 1000); // 1 second delay for DOM ready + } + }; + + chrome.tabs.onUpdated.addListener(checkTabLoaded); + + } catch (error) { + console.error("Error in handleScanProductsRequest:", error); + sendResponse({ ok: false, error: error.message || "Unknown error" }); + } +} + +/** + * Handles scan complete response from content script + */ +function handleScanComplete(tabId, data) { + cleanupScanRequest(tabId, data, null); +} + +/** + * Cleans up scan request: closes tab, clears timeout, sends response + */ +async function cleanupScanRequest(tabId, data, error) { + const request = activeScanRequests.get(tabId); + if (!request) return; + + // Clear timeout + if (request.timeout) { + clearTimeout(request.timeout); + } + + // Remove from active requests + activeScanRequests.delete(tabId); + + // Close tab (always, even on error) + try { + await chrome.tabs.remove(tabId); + } catch (err) { + // Tab might already be closed + console.warn("Could not close tab:", err); + } + + // Send response + if (request.sendResponse) { + if (error) { + request.sendResponse(error); + } else if (data) { + request.sendResponse({ ok: true, data: data }); + } else { + request.sendResponse({ ok: false, error: "Unknown error" }); + } + } +} + export async function getJwt() { const data = await chrome.storage.local.get(STORAGE_KEY); diff --git a/Extension/content-script.js b/Extension/content-script.js index d839291..43113c0 100644 --- a/Extension/content-script.js +++ b/Extension/content-script.js @@ -3,20 +3,62 @@ const MESSAGE_SOURCE = "eship-webapp"; -// Markiere Extension als verfügbar -// #region agent log -try { - console.log('[ESHIP-CONTENT] Content script loaded'); - if (typeof window !== 'undefined') { - window.__EBAY_EXTENSION__ = true; - console.log('[ESHIP-CONTENT] window.__EBAY_EXTENSION__ set to true'); - } else { - console.error('[ESHIP-CONTENT] window is undefined!'); +// Markiere Extension als verfügbar - MEHRFACH versuchen, da Timing variieren kann +function setExtensionFlag() { + try { + const hasChrome = typeof chrome !== 'undefined'; + const hasRuntime = hasChrome && chrome.runtime; + const runtimeId = hasRuntime ? chrome.runtime.id : null; + if (typeof window !== 'undefined' && hasChrome && hasRuntime && runtimeId) { + window.__EBAY_EXTENSION__ = true; + window.__EBAY_EXTENSION_ID__ = runtimeId; // Extension-ID für chrome.runtime.sendMessage + console.log('[ESHIP-CONTENT] window.__EBAY_EXTENSION__ set to true, ID:', runtimeId); + return true; + } + } catch (e) { + console.error('[ESHIP-CONTENT] Error setting flag:', e); } -} catch (e) { - console.error('[ESHIP-CONTENT] Error setting flag:', e); + return false; } -// #endregion + +// Versuche Flag sofort zu setzen +console.log('[ESHIP-CONTENT] Content script loaded'); +if (!setExtensionFlag()) { + // Wenn window nicht verfügbar, warte auf DOMContentLoaded oder document.readyState + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + setExtensionFlag(); + }); + } else { + // DOM ist bereits geladen, versuche nochmal + setTimeout(() => { + setExtensionFlag(); + }, 0); + } +} + +// Sende Extension-ID an Web-App via postMessage (da Content Script Isolation verhindert, dass window-Properties geteilt werden) +// Die Web-App kann dann die Extension-ID in ihrem eigenen Context speichern +function sendExtensionIdToWebApp() { + try { + const runtimeId = chrome.runtime?.id; + if (runtimeId) { + // Sende Extension-ID an Web-App + window.postMessage({ + source: "eship-extension", + type: "EXTENSION_ID", + extensionId: runtimeId + }, "*"); + } + } catch (e) { + console.error('[ESHIP-CONTENT] Error sending extension ID:', e); + } +} + +// Sende Extension-ID beim Laden +sendExtensionIdToWebApp(); +// Auch nach kurzer Verzögerung nochmal (falls Web-App noch nicht bereit ist) +setTimeout(sendExtensionIdToWebApp, 500); window.addEventListener("message", (event) => { // Sicherheitscheck: Nur Nachrichten von derselben Origin akzeptieren diff --git a/Extension/ebay-content-script.js b/Extension/ebay-content-script.js index 344be80..5d1d6e0 100644 --- a/Extension/ebay-content-script.js +++ b/Extension/ebay-content-script.js @@ -24,6 +24,21 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { } return true; // async response } + + if (message.action === "PARSE_PRODUCT_LIST") { + try { + const items = parseProductList(); + sendResponse({ ok: true, data: { items } }); + } catch (error) { + // Niemals unhandled throws - immer graceful response + console.error("Error parsing product list:", error); + sendResponse({ + ok: false, + error: error.message || "Failed to parse product list" + }); + } + return true; // async response + } }); /** @@ -143,7 +158,27 @@ function extractSellerId() { */ function extractShopName() { try { - // Methode 1: Spezifische Selektoren versuchen + // Methode 1: Shop-Name aus Storefront-Link extrahieren + // Pattern: Shop Name + try { + const storefrontLinks = document.querySelectorAll('a[href*="/str/"]'); + for (const link of storefrontLinks) { + // Prüfe ob Link data-track Attribut hat (typisch für Storefront-Links) + if (link.hasAttribute('data-track') || link.href.includes('/str/')) { + const linkText = link.textContent?.trim(); + if (linkText && linkText.length > 0 && linkText.length < 200) { + // Prüfe dass es nicht nur ein URL-Pfad ist + if (!linkText.match(/^https?:\/\//) && !linkText.match(/^\/str\//)) { + return linkText; + } + } + } + } + } catch (e) { + // Continue to next method + } + + // Methode 2: Spezifische Selektoren versuchen const shopNameSelectors = [ 'h1.shop-name', '.store-name', @@ -169,7 +204,7 @@ function extractShopName() { } } - // Methode 2: document.title parsen + // Methode 3: document.title parsen try { const title = document.title || ""; // Versuche Muster wie "Shop Name | eBay" zu extrahieren @@ -185,7 +220,7 @@ function extractShopName() { // Continue } - // Methode 3: h1 Tag als Fallback + // Methode 4: h1 Tag als Fallback try { const h1 = document.querySelector('h1'); if (h1) { @@ -204,6 +239,71 @@ function extractShopName() { } } +/** + * Extrahiert "Artikel verkauft" aus Storefront-Profilen + * @returns {number|null} Anzahl verkaufter Artikel oder null + */ +function extractItemsSold() { + try { + // Suche nach Container + const container = document.querySelector(".str-seller-card__store-stats-content"); + if (!container) { + return null; + } + + // Finde div children, die "Artikel verkauft" enthalten + const divs = container.querySelectorAll("div"); + for (const div of divs) { + const divText = div.textContent || ""; + if (divText.includes("Artikel verkauft")) { + // Suche nach span mit Klasse str-text-span BOLD (Klasse kann als "str-text-span BOLD" sein) + const span1 = div.querySelector("span.str-text-span.BOLD"); + const span2 = div.querySelector("span.BOLD"); + const span3 = div.querySelector('span[class*="BOLD"]'); + const span = span1 || span2 || span3; + if (span) { + let valueText = span.textContent?.trim() || ""; + + // Normalisierung: Entferne Leerzeichen + valueText = valueText.replace(/\s/g, ""); + + // Ersetze Tausendertrenner (. und ,) durch leeren String + valueText = valueText.replace(/[.,]/g, ""); + + // Nur Digits behalten + valueText = valueText.replace(/\D/g, ""); + + // Parse zu Integer + if (valueText.length > 0) { + const parsedValue = parseInt(valueText, 10); + if (!isNaN(parsedValue) && parsedValue >= 0) { + return parsedValue; + } + } + } + + // Fallback: Regex auf div-Text, falls Struktur abweicht + const regexMatch = divText.match(/([\d.,]+)\s*Artikel\s*verkauft/i); + if (regexMatch && regexMatch[1]) { + let valueText = regexMatch[1].trim(); + valueText = valueText.replace(/\s/g, "").replace(/[.,]/g, "").replace(/\D/g, ""); + if (valueText.length > 0) { + const parsedValue = parseInt(valueText, 10); + if (!isNaN(parsedValue) && parsedValue >= 0) { + return parsedValue; + } + } + } + } + } + + return null; + } catch (e) { + // Graceful fallback bei Fehlern + return null; + } +} + /** * Extrahiert Stats aus DOM (Feedback Score, Positive Rate, etc.) * @returns {object} Stats Objekt @@ -320,6 +420,16 @@ function extractStats() { // Continue } + // Items Sold (Artikel verkauft) + try { + const itemsSold = extractItemsSold(); + if (itemsSold !== null) { + stats.itemsSold = itemsSold; + } + } catch (e) { + // Continue + } + } catch (e) { // Return empty stats object } @@ -358,4 +468,266 @@ function parseEbayPage() { stats: {} }; } +} + +/** + * Parst Produktliste von eBay Storefront oder Seller Listings + * @returns {Array} Array von Produkt-Items + */ +function parseProductList() { + try { + const url = window.location.href; + const urlLower = url.toLowerCase(); + + // Determine page type + const isStorePage = urlLower.includes('/str/') || urlLower.includes('/store/'); + const isSellerPage = urlLower.includes('/usr/'); + + // Check if seller profile without items (try to find link to listings) + if (isSellerPage && !isStorePage) { + const itemsLink = document.querySelector('a[href*="/usr/"][href*="?items="]') || + document.querySelector('a[href*="schid=mksr"]') || + Array.from(document.querySelectorAll('a')).find(a => { + const text = (a.textContent || '').toLowerCase(); + return text.includes('artikel') || text.includes('angebote') || + text.includes('items for sale') || text.includes('see all items'); + }); + + if (!itemsLink) { + // Try to find item cards directly + const hasItems = findItemLinks().length > 0; + if (!hasItems) { + throw new Error("no_items_page"); + } + } + } + + // Extract items + const items = findItemLinks(); + + if (items.length === 0) { + throw new Error("no_items_found"); + } + + // Parse each item + const parsedItems = []; + const seenIds = new Set(); + + for (const itemLink of items) { + try { + const item = parseItemFromLink(itemLink); + + // Deduplicate by platformProductId + if (item.platformProductId && !seenIds.has(item.platformProductId)) { + seenIds.add(item.platformProductId); + parsedItems.push(item); + } + } catch (e) { + // Continue with next item if one fails + console.warn("Failed to parse item:", e); + } + } + + // Return max 60 items (first page) + return parsedItems.slice(0, 60); + + } catch (error) { + // Re-throw to be caught by message handler + throw error; + } +} + +/** + * Findet Item-Links auf der Seite + * @returns {Array} Array von Link-Elementen + */ +function findItemLinks() { + const links = []; + + try { + // Multiple selector fallbacks for item cards + const selectors = [ + 'a[href*="/itm/"]', // Direct item links + '.s-item a[href*="/itm/"]', // Search result items + '.srp-results .s-item a', // Search results + '.ebay-item-card a[href*="/itm/"]', // Item cards + '[class*="item-card"] a[href*="/itm/"]', // Generic item cards + ]; + + for (const selector of selectors) { + try { + const found = document.querySelectorAll(selector); + if (found.length > 0) { + // Filter out duplicates by href + const hrefs = new Set(); + for (const link of found) { + const href = link.href || link.getAttribute('href'); + if (href && href.includes('/itm/') && !hrefs.has(href)) { + hrefs.add(href); + links.push(link); + } + } + if (links.length > 0) break; // Found items, stop trying other selectors + } + } catch (e) { + // Continue to next selector + } + } + } catch (e) { + // Return empty array on error + } + + return links; +} + +/** + * Parst ein einzelnes Item aus einem Link-Element + * @param {Element} itemLink - Link-Element zu einem eBay-Item + * @returns {object} Parsed Item-Data + */ +function parseItemFromLink(itemLink) { + const item = { + platformProductId: null, + title: "", + price: null, + currency: null, + url: "", + status: "active", + category: null, + condition: null + }; + + try { + // URL (absolute) + const href = itemLink.href || itemLink.getAttribute('href'); + if (href) { + item.url = href.startsWith('http') ? href : new URL(href, window.location.origin).href; + + // Extract platformProductId from URL: /itm/ or ?item= + const itmMatch = item.url.match(/\/itm\/(\d+)/); + if (itmMatch && itmMatch[1]) { + item.platformProductId = itmMatch[1]; + } else { + const itemParamMatch = item.url.match(/[?&]item=(\d+)/); + if (itemParamMatch && itemParamMatch[1]) { + item.platformProductId = itemParamMatch[1]; + } + } + } + + // Fallback: data attributes if present + if (!item.platformProductId) { + const dataItemId = itemLink.getAttribute('data-item-id') || + itemLink.closest('[data-item-id]')?.getAttribute('data-item-id'); + if (dataItemId) { + item.platformProductId = dataItemId; + } + } + + // Title: from link text or title element + try { + const titleElement = itemLink.querySelector('.s-item__title') || + itemLink.querySelector('[class*="title"]') || + itemLink.closest('.s-item')?.querySelector('.s-item__title'); + + if (titleElement) { + item.title = titleElement.textContent?.trim() || ""; + } else { + // Fallback: link text itself + item.title = itemLink.textContent?.trim() || ""; + } + + // Normalize title (remove extra whitespace) + item.title = item.title.replace(/\s+/g, ' ').trim(); + } catch (e) { + // Continue without title + } + + // Price + Currency + try { + const itemCard = itemLink.closest('.s-item') || itemLink.closest('[class*="item-card"]'); + if (itemCard) { + const priceElement = itemCard.querySelector('.s-item__price') || + itemCard.querySelector('[class*="price"]') || + itemCard.querySelector('.BOLD'); + + if (priceElement) { + const priceText = priceElement.textContent?.trim() || ""; + const parsed = parsePrice(priceText); + item.price = parsed.price; + item.currency = parsed.currency; + } + } + } catch (e) { + // Continue without price + } + + // Category (optional) + try { + const categoryElement = itemLink.closest('.s-item')?.querySelector('[class*="category"]'); + if (categoryElement) { + item.category = categoryElement.textContent?.trim() || null; + } + } catch (e) { + // Continue without category + } + + // Condition (optional) + try { + const conditionElement = itemLink.closest('.s-item')?.querySelector('[class*="condition"]'); + if (conditionElement) { + item.condition = conditionElement.textContent?.trim() || null; + } + } catch (e) { + // Continue without condition + } + + // Status: default "active" (storefront shows active listings) + // Could check for "ended" indicators, but MVP keeps it simple + item.status = "active"; + + } catch (e) { + // Continue with partial data + console.warn("Error parsing item:", e); + } + + return item; +} + +/** + * Parst Preis-String in Zahl und Währung + * @param {string} priceText - Preis-String z.B. "EUR 12,99" oder "$15.50" + * @returns {object} { price: number|null, currency: string|null } + */ +function parsePrice(priceText) { + const result = { price: null, currency: null }; + + try { + if (!priceText) return result; + + // Extract currency symbols/codes + const currencyMatch = priceText.match(/(EUR|USD|GBP|€|\$|£)/i); + if (currencyMatch) { + const currencyCode = currencyMatch[1].toUpperCase(); + if (currencyCode === '€') result.currency = 'EUR'; + else if (currencyCode === '$') result.currency = 'USD'; + else if (currencyCode === '£') result.currency = 'GBP'; + else result.currency = currencyCode; + } + + // Extract numeric value (handle both comma and dot as decimal separator) + const normalized = priceText + .replace(/[^\d,.-]/g, '') // Remove non-numeric except , . - + .replace(/\./g, '') // Remove thousand separators (assume dot) + .replace(',', '.'); // Replace comma with dot for decimal + + const price = parseFloat(normalized); + if (!isNaN(price) && price >= 0) { + result.price = price; + } + } catch (e) { + // Return null values on error + } + + return result; } \ No newline at end of file