diff --git a/.cursor/debug.log b/.cursor/debug.log
deleted file mode 100644
index be9f56d..0000000
--- a/.cursor/debug.log
+++ /dev/null
@@ -1,278 +0,0 @@
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032347685,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032347686,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032347686,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032347694,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032347694,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032347696,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118967,"url":""},"timestamp":1769032347707,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348580,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348582,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348621,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348967,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348970,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348974,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348975,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348978,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348979,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348980,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032348980,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118967,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032349179,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118967,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032349180,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118967,"attempt":0},"timestamp":1769032351183,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118967,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032351184,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118967},"timestamp":1769032351183,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118967},"timestamp":1769032351184,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118967,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032351184,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118967},"timestamp":1769032351185,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118967,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032351186,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118967,"frameId":0},"timestamp":1769032351187,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118967},"timestamp":1769032351188,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118967,"pingAttempt":0},"timestamp":1769032351494,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118967,"pingAttempt":0},"timestamp":1769032351495,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118967,"injected":true},"timestamp":1769032351495,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118967,"attempt":0},"timestamp":1769032351496,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118967,"hasResponse":true,"ok":true},"timestamp":1769032351497,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032351513,"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":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728}},"timestamp":1769032351513,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1769032351513,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032351603,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032358262,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032358264,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032358263,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032358275,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032358276,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032358277,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118969,"url":""},"timestamp":1769032358289,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118969,"status":"loading","url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi"},"timestamp":1769032358785,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118969,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi"},"timestamp":1769032358836,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118969,"status":"complete","url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi"},"timestamp":1769032358892,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118969,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi","isEbayUrl":true},"timestamp":1769032358892,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118969,"attempt":0},"timestamp":1769032360901,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118969},"timestamp":1769032360901,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118969,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi","isEbayUrl":true},"timestamp":1769032360902,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118969},"timestamp":1769032360902,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118969,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032361126,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118969},"timestamp":1769032361127,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118969,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=a41c5b80-ed2d-4186-a1f1-e146e4aee0f1&iim=aMTQ1LjR&iia=HOIyNC43wL&iiz=YnjMy4yMjU*Doi"},"timestamp":1769032361128,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118969,"frameId":0},"timestamp":1769032361130,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118969},"timestamp":1769032361132,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118969,"pingAttempt":0},"timestamp":1769032361443,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118969,"pingAttempt":0},"timestamp":1769032361444,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118969,"injected":true},"timestamp":1769032361444,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118969,"attempt":0},"timestamp":1769032361445,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118969,"hasResponse":true,"ok":true},"timestamp":1769032361446,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":null,"stats":{"itemsSold":null}},"timestamp":1769032361460,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_shop_name":"Bitte bestätigen Sie zum Fortfahren Ihre Identität","account_sells":null}},"timestamp":1769032361460,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_shop_name":"Bitte bestätigen Sie zum Fortfahren Ihre Identität"},"payloadKeys":["account_platform_market","account_shop_name"]},"timestamp":1769032361460,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032361564,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032441216,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032441217,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032441216,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032441224,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032441225,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032441226,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118971,"url":""},"timestamp":1769032441238,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118971,"status":"loading","url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR"},"timestamp":1769032441726,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118971,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR"},"timestamp":1769032441732,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118971,"status":"complete","url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR"},"timestamp":1769032441786,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118971,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR","isEbayUrl":true},"timestamp":1769032441786,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118971,"attempt":0},"timestamp":1769032443790,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118971},"timestamp":1769032443791,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118971,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR","isEbayUrl":true},"timestamp":1769032443792,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118971},"timestamp":1769032443792,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118971,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032443793,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118971},"timestamp":1769032443793,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118971,"url":"https://www.ebay.de/splashui/captcha?ap=1&appName=orch&ru=https%3A%2F%2Fwww.ebay.de%2Fstr%2Fsbdirect24%3F_trksid%3Dp4429486.m3561.l161211&iid=1bd50360-556b-409a-951f-01bca5aaf679&iim=GMTQ1Ljm&iia=hsIyNC43kV&iiz=zlQMy4yMjU*eRR"},"timestamp":1769032443794,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118971,"frameId":0},"timestamp":1769032443795,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118971},"timestamp":1769032443797,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118971,"pingAttempt":0},"timestamp":1769032444100,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118971,"pingAttempt":0},"timestamp":1769032444101,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118971,"injected":true},"timestamp":1769032444102,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118971,"attempt":0},"timestamp":1769032444102,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118971,"hasResponse":true,"ok":true},"timestamp":1769032444103,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":null,"stats":{"itemsSold":null}},"timestamp":1769032444116,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_shop_name":"Bitte bestätigen Sie zum Fortfahren Ihre Identität","account_sells":null}},"timestamp":1769032444116,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_shop_name":"Bitte bestätigen Sie zum Fortfahren Ihre Identität"},"payloadKeys":["account_platform_market","account_shop_name"]},"timestamp":1769032444117,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032444203,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032465359,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032465359,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032465359,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032465366,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032465366,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032465367,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118975,"url":""},"timestamp":1769032465376,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466284,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466287,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466315,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466656,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466659,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466663,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466663,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466664,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466665,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466667,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466667,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118975,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032466804,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118975,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032466804,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118975,"attempt":0},"timestamp":1769032468807,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118975},"timestamp":1769032468808,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118975,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032468808,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118975},"timestamp":1769032468808,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118975,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032468809,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118975},"timestamp":1769032468809,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118975,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032468809,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118975,"frameId":0},"timestamp":1769032468811,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118975},"timestamp":1769032468812,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118975,"pingAttempt":0},"timestamp":1769032469121,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118975,"pingAttempt":0},"timestamp":1769032469122,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118975,"injected":true},"timestamp":1769032469123,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118975,"attempt":0},"timestamp":1769032469123,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118975,"hasResponse":true,"ok":true},"timestamp":1769032469124,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032469138,"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":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728}},"timestamp":1769032469138,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1769032469139,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032469243,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032683600,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032683601,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032683601,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032683609,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032683609,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032683610,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118977,"url":""},"timestamp":1769032683621,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032684632,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032684634,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032684639,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685105,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685108,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685112,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685113,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685114,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685115,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685116,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685117,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118977,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032685262,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118977,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032685263,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118977,"attempt":0},"timestamp":1769032687278,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118977},"timestamp":1769032687278,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118977,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032687279,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118977},"timestamp":1769032687279,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118977,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032687280,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118977},"timestamp":1769032687281,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118977,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032687281,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118977,"frameId":0},"timestamp":1769032687283,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118977},"timestamp":1769032687284,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118977,"pingAttempt":0},"timestamp":1769032687590,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118977,"pingAttempt":0},"timestamp":1769032687591,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118977,"injected":true},"timestamp":1769032687591,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118977,"attempt":0},"timestamp":1769032687591,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118977,"hasResponse":true,"ok":true},"timestamp":1769032687593,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032687608,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1769032687608,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032687693,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032795025,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032795025,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032795080,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118979,"url":""},"timestamp":1769032795089,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796012,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796014,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796026,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796358,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796361,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796365,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796365,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796366,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796367,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796368,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796368,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118979,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032796823,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118979,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032796823,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118979,"attempt":0},"timestamp":1769032798837,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118979},"timestamp":1769032798837,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118979,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032798838,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118979},"timestamp":1769032798838,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118979,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032798839,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118979},"timestamp":1769032798839,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118979,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032798840,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118979,"frameId":0},"timestamp":1769032798841,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118979},"timestamp":1769032798842,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118979,"pingAttempt":0},"timestamp":1769032799147,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118979,"pingAttempt":0},"timestamp":1769032799149,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118979,"injected":true},"timestamp":1769032799149,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118979,"attempt":0},"timestamp":1769032799149,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118979,"hasResponse":true,"ok":true},"timestamp":1769032799151,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032799167,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1769032799168,"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":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728}},"timestamp":1769032799167,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032799416,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032812193,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032812190,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032812190,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118983,"url":""},"timestamp":1769032812203,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813057,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813059,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813069,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813381,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813384,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813387,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813388,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813389,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813390,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813391,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813392,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118983,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032813527,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118983,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032813527,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118983,"attempt":0},"timestamp":1769032815528,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118983},"timestamp":1769032815529,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118983,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032815529,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118983},"timestamp":1769032815529,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118983,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032815530,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118983},"timestamp":1769032815531,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118983,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032815531,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118983,"frameId":0},"timestamp":1769032815533,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118983},"timestamp":1769032815535,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118983,"pingAttempt":0},"timestamp":1769032815838,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118983,"pingAttempt":0},"timestamp":1769032815839,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118983,"injected":true},"timestamp":1769032815839,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118983,"attempt":0},"timestamp":1769032815839,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118983,"hasResponse":true,"ok":true},"timestamp":1769032815841,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032815854,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1769032815855,"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":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728}},"timestamp":1769032815854,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032815938,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032819428,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1769032819429,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:165","message":"parseViaExtension: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","hasChrome":true,"hasRuntime":true},"timestamp":1769032819429,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:175","message":"parseViaExtension: got extension ID","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032819437,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"ebayParserService.js:178","message":"parseViaExtension: sending message","data":{"extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032819437,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:73","message":"handleParseRequest: entry","data":{"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032819438,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:89","message":"handleParseRequest: tab created","data":{"tabId":1015118985,"url":""},"timestamp":1769032819449,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820280,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820282,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820287,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820626,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820629,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820633,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820634,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820635,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820636,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820637,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"loading","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820638,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:104","message":"checkTabLoaded: tab update","data":{"tabId":1015118985,"status":"complete","url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032820785,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:108","message":"checkTabLoaded: tab complete","data":{"tabId":1015118985,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032820786,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:187","message":"sendParseMessageWithRetry: entry","data":{"tabId":1015118985,"attempt":0},"timestamp":1769032822797,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"background.js:143","message":"ensureContentScriptInjected: entry","data":{"tabId":1015118985},"timestamp":1769032822798,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:147","message":"ensureContentScriptInjected: tab info","data":{"tabId":1015118985,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211","isEbayUrl":true},"timestamp":1769032822798,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
-{"location":"background.js:153","message":"ensureContentScriptInjected: sending PING","data":{"tabId":1015118985},"timestamp":1769032822798,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:158","message":"ensureContentScriptInjected: PING failed","data":{"tabId":1015118985,"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1769032822799,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:162","message":"ensureContentScriptInjected: attempting injection","data":{"tabId":1015118985},"timestamp":1769032822799,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
-{"location":"background.js:165","message":"ensureContentScriptInjected: tab info before injection","data":{"tabId":1015118985,"url":"https://www.ebay.de/str/sbdirect24?_trksid=p4429486.m3561.l161211"},"timestamp":1769032822800,"sessionId":"debug-session","runId":"run1","hypothesisId":"F"}
-{"location":"background.js:172","message":"ensureContentScriptInjected: listener injection success","data":{"tabId":1015118985,"frameId":0},"timestamp":1769032822801,"sessionId":"debug-session","runId":"run1","hypothesisId":"H"}
-{"location":"background.js:207","message":"ensureContentScriptInjected: test injection success","data":{"tabId":1015118985},"timestamp":1769032822802,"sessionId":"debug-session","runId":"run1","hypothesisId":"G"}
-{"location":"background.js:169","message":"ensureContentScriptInjected: ping after injection","data":{"tabId":1015118985,"pingAttempt":0},"timestamp":1769032823107,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:176","message":"ensureContentScriptInjected: ping success after injection","data":{"tabId":1015118985,"pingAttempt":0},"timestamp":1769032823108,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:195","message":"sendParseMessageWithRetry: injection result","data":{"tabId":1015118985,"injected":true},"timestamp":1769032823109,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"background.js:204","message":"sendParseMessageWithRetry: sending PARSE_EBAY","data":{"tabId":1015118985,"attempt":0},"timestamp":1769032823109,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"background.js:206","message":"sendParseMessageWithRetry: response received","data":{"tabId":1015118985,"hasResponse":true,"ok":true},"timestamp":1769032823111,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
-{"location":"ebayParserService.js:196","message":"parseViaExtension: response success","data":{"hasStats":true,"itemsSold":348728,"stats":{"itemsSold":348728}},"timestamp":1769032823124,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
-{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"69714472002ab5f0dd0e","payload":{"account_platform_market":"DE","account_platform_account_id":"sbdirect24","account_shop_name":"sbdirect24","account_sells":348728,"account_updated_at":"2026-01-21T22:00:23.125Z"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells","account_updated_at"]},"timestamp":1769032823125,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
-{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"69714472002ab5f0dd0e"},"timestamp":1769032823218,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
diff --git a/Extension/background.js b/Extension/background.js
index b194cfe..9038d0b 100644
--- a/Extension/background.js
+++ b/Extension/background.js
@@ -2,9 +2,12 @@ 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 SCAN_TIMEOUT_MS = 45000; // 45 seconds (listing with _ipg=240 can be slow)
const activeParseRequests = new Map(); // Map
-const activeScanRequests = new Map(); // Map
+const activeScanRequests = new Map(); // Map;
+
+/** Aktueller Scan-Fortschritt für GET_SCAN_PROGRESS (Polling durch Web-App) */
+let currentScanProgress = null;
// Messages from content script (der von der Web-App kommt)
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
@@ -64,6 +67,11 @@ chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => {
handleScanProductsRequest(msg.url, msg.accountId, sendResponse);
return true; // async
}
+
+ if (msg?.action === "GET_SCAN_PROGRESS") {
+ sendResponse(currentScanProgress ?? { percent: 0, phase: "idle", total: 0, current: 0, complete: false });
+ return false;
+ }
});
/**
@@ -72,10 +80,6 @@ chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => {
*/
async function handleParseRequest(url, sendResponse) {
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:73',message:'handleParseRequest: entry',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
// Validate URL
if (!url || typeof url !== 'string' || !url.toLowerCase().includes('ebay.')) {
sendResponse({ ok: false, error: "Invalid eBay URL" });
@@ -92,10 +96,6 @@ async function handleParseRequest(url, sendResponse) {
const tabId = tab.id;
console.log("[BACKGROUND] Tab created:", tabId);
-
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:89',message:'handleParseRequest: tab created',data:{tabId,url:tab.url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
// Set up timeout
const timeoutId = setTimeout(() => {
@@ -112,19 +112,11 @@ async function handleParseRequest(url, sendResponse) {
const checkTabLoaded = (updatedTabId, changeInfo, updatedTab) => {
if (updatedTabId !== tabId) return;
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:104',message:'checkTabLoaded: tab update',data:{tabId:updatedTabId,status:changeInfo.status,url:updatedTab.url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
- // #endregion
-
// Tab is fully loaded
if (changeInfo.status === 'complete' && updatedTab.url) {
chrome.tabs.onUpdated.removeListener(checkTabLoaded);
console.log("[BACKGROUND] Tab loaded, sending parse message:", updatedTab.url);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:108',message:'checkTabLoaded: tab complete',data:{tabId,url:updatedTab.url,isEbayUrl:isEbayUrl(updatedTab.url)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
- // #endregion
-
// Wait longer for content script to auto-load (if it does)
// Content scripts from manifest.json might need more time in hidden tabs
setTimeout(() => {
@@ -159,17 +151,9 @@ function isEbayUrl(url) {
*/
async function ensureContentScriptInjected(tabId) {
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:143',message:'ensureContentScriptInjected: entry',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
// First, check if tab URL is an eBay URL
const tab = await chrome.tabs.get(tabId);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:147',message:'ensureContentScriptInjected: tab info',data:{tabId,url:tab.url,isEbayUrl:isEbayUrl(tab.url)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
- // #endregion
-
if (!isEbayUrl(tab.url)) {
console.log("[BACKGROUND] Tab is not an eBay URL:", tab.url);
return false;
@@ -177,157 +161,27 @@ async function ensureContentScriptInjected(tabId) {
// Check if content script is already loaded by sending a ping
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:153',message:'ensureContentScriptInjected: sending PING',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
await chrome.tabs.sendMessage(tabId, { action: "PING" });
console.log("[BACKGROUND] Content script already loaded");
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:156',message:'ensureContentScriptInjected: PING success',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
return true;
} catch (pingError) {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:158',message:'ensureContentScriptInjected: PING failed',data:{tabId,error:pingError.message,runtimeError:chrome.runtime.lastError?.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
// Content script not loaded, try to inject it manually
console.log("[BACKGROUND] Content script not found, injecting manually...");
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:162',message:'ensureContentScriptInjected: attempting injection',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{});
- // #endregion
-
// Get tab info to check frames
const tabInfo = await chrome.tabs.get(tabId);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:165',message:'ensureContentScriptInjected: tab info before injection',data:{tabId,url:tabInfo.url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'F'})}).catch(()=>{});
- // #endregion
-
- // Inject the message listener directly as a function (not as a file)
- // This ensures it runs in the correct context with access to chrome.runtime
+ // Inject full ebay-content-script.js so PING, PARSE_EBAY and PARSE_PRODUCT_LIST are all handled.
+ // The previous inline injection only handled PING+PARSE_EBAY; SCAN sends PARSE_PRODUCT_LIST.
try {
await chrome.scripting.executeScript({
target: { tabId: tabId, frameIds: [0] },
- func: () => {
- // Register message listener directly
- if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.onMessage) {
- chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
- if (message.action === "PING") {
- sendResponse({ ok: true, ready: true });
- return true;
- }
-
- if (message.action === "PARSE_EBAY") {
- // Simple parsing - extract from URL and DOM
- try {
- const url = window.location.href;
- const hostname = window.location.hostname.toLowerCase();
-
- // Extract market
- let market = "US";
- if (hostname.includes('.de')) market = 'DE';
- else if (hostname.includes('.uk')) market = 'UK';
- else if (hostname.includes('.fr')) market = 'FR';
- else if (hostname.includes('.it')) market = 'IT';
- else if (hostname.includes('.es')) market = 'ES';
-
- // Extract seller ID from URL
- let sellerId = "";
- const usrMatch = url.match(/\/usr\/([^\/\?]+)/i);
- if (usrMatch && usrMatch[1]) {
- sellerId = usrMatch[1].trim();
- } else {
- const strMatch = url.match(/\/str\/([^\/\?]+)/i);
- if (strMatch && strMatch[1]) {
- sellerId = strMatch[1].trim();
- }
- }
-
- // Extract shop name
- let shopName = "";
- try {
- const h1 = document.querySelector('h1');
- if (h1) {
- shopName = h1.textContent?.trim() || "";
- }
- } catch (e) {}
-
- // Extract items sold
- let itemsSold = null;
- try {
- const container = document.querySelector(".str-seller-card__store-stats-content");
- if (container) {
- const divs = container.querySelectorAll("div");
- for (const div of divs) {
- const divText = div.textContent || "";
- if (divText.includes("Artikel verkauft")) {
- const span = div.querySelector('span[class*="BOLD"]') || div.querySelector("span.BOLD");
- if (span) {
- let valueText = span.textContent?.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) {
- itemsSold = parsedValue;
- }
- }
- }
- }
- }
- }
- } catch (e) {}
-
- sendResponse({
- ok: true,
- data: {
- sellerId: sellerId || "",
- shopName: shopName || "",
- market: market,
- status: (sellerId || shopName) ? "active" : "unknown",
- stats: {
- itemsSold: itemsSold
- }
- }
- });
- } catch (error) {
- sendResponse({
- ok: true,
- data: {
- sellerId: "",
- shopName: "",
- market: "US",
- status: "unknown",
- stats: {}
- }
- });
- }
- return true;
- }
-
- return false;
- });
-
- console.log("[EBAY-CONTENT] Message listener registered");
- }
- }
+ files: ["ebay-content-script.js"]
});
- console.log("[BACKGROUND] Content script message listener injected successfully");
-
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:172',message:'ensureContentScriptInjected: listener injection success',data:{tabId,frameId:0},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H'})}).catch(()=>{});
- // #endregion
+ console.log("[BACKGROUND] ebay-content-script.js injected successfully");
} catch (injectError) {
- console.error("[BACKGROUND] Failed to inject message listener:", injectError);
-
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:178',message:'ensureContentScriptInjected: listener injection failed',data:{tabId,error:injectError.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H'})}).catch(()=>{});
- // #endregion
-
+ console.error("[BACKGROUND] Failed to inject ebay-content-script:", injectError);
throw injectError;
}
@@ -337,31 +191,11 @@ async function ensureContentScriptInjected(tabId) {
target: { tabId: tabId, frameIds: [0] },
func: () => {
console.log("[TEST-INJECTION] Test script executed in main frame");
- // Try to send a log via fetch
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{
- method:'POST',
- headers:{'Content-Type':'application/json'},
- body:JSON.stringify({
- location:'background.js:test-injection',
- message:'test injection: script executed',
- data:{url:window.location.href,hasChrome:typeof chrome!=='undefined',hasRuntime:typeof chrome!=='undefined'&&!!chrome.runtime},
- timestamp:Date.now(),
- sessionId:'debug-session',
- runId:'run1',
- hypothesisId:'G'
- })
- }).catch(()=>{});
}
});
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:207',message:'ensureContentScriptInjected: test injection success',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'G'})}).catch(()=>{});
- // #endregion
- } catch (testError) {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:210',message:'ensureContentScriptInjected: test injection failed',data:{tabId,error:testError.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'G'})}).catch(()=>{});
- // #endregion
- }
+ } catch (testError) {
+ }
// Wait longer for the script to fully initialize and register message listeners
// Retry PING to verify the script is ready
@@ -370,10 +204,6 @@ async function ensureContentScriptInjected(tabId) {
await new Promise(resolve => setTimeout(resolve, 300)); // 300ms between pings
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:169',message:'ensureContentScriptInjected: ping after injection',data:{tabId,pingAttempt},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
// Try sending to main frame explicitly
try {
await chrome.tabs.sendMessage(tabId, { action: "PING" }, { frameId: 0 });
@@ -382,44 +212,25 @@ async function ensureContentScriptInjected(tabId) {
await chrome.tabs.sendMessage(tabId, { action: "PING" });
}
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:176',message:'ensureContentScriptInjected: ping success after injection',data:{tabId,pingAttempt},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
console.log("[BACKGROUND] Content script ready after injection");
return true;
} catch (pingErr) {
// Continue to next attempt
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:182',message:'ensureContentScriptInjected: ping failed after injection',data:{tabId,pingAttempt,error:pingErr.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
- }
+ }
}
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:189',message:'ensureContentScriptInjected: ping timeout after injection',data:{tabId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
// Even if PING failed, return true - the script might still work
console.warn("[BACKGROUND] Content script injected but PING not responding");
return true;
} catch (injectError) {
console.error("[BACKGROUND] Failed to inject content script:", injectError);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:172',message:'ensureContentScriptInjected: injection failed',data:{tabId,error:injectError.message,runtimeError:chrome.runtime.lastError?.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{});
- // #endregion
-
return false;
}
}
} catch (error) {
console.error("[BACKGROUND] Error checking/injecting content script:", error);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:177',message:'ensureContentScriptInjected: error',data:{tabId,error:error.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
return false;
}
}
@@ -436,18 +247,10 @@ async function sendParseMessageWithRetry(tabId, attempt) {
try {
console.log(`[BACKGROUND] Sending parse message (attempt ${attempt + 1}/${maxAttempts}) to tab:`, tabId);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:187',message:'sendParseMessageWithRetry: entry',data:{tabId,attempt},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
- // #endregion
-
// On first attempt, ensure content script is injected
if (attempt === 0) {
const injected = await ensureContentScriptInjected(tabId);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:195',message:'sendParseMessageWithRetry: injection result',data:{tabId,injected},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
if (!injected) {
throw new Error("Could not inject content script");
}
@@ -455,10 +258,6 @@ async function sendParseMessageWithRetry(tabId, attempt) {
// Check if content script is injected by trying to send a ping
// If this fails, the content script might not be loaded yet
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:204',message:'sendParseMessageWithRetry: sending PARSE_EBAY',data:{tabId,attempt},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
// Try sending to main frame explicitly first
let response;
try {
@@ -470,10 +269,6 @@ async function sendParseMessageWithRetry(tabId, attempt) {
console.log("[BACKGROUND] Parse response received:", response);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:206',message:'sendParseMessageWithRetry: response received',data:{tabId,hasResponse:!!response,ok:response?.ok},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
if (response && response.ok && response.data) {
handleParseComplete(tabId, response.data);
} else {
@@ -498,10 +293,6 @@ async function sendParseMessageWithRetry(tabId, attempt) {
isContentScriptError: isContentScriptError
});
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'background.js:217',message:'sendParseMessageWithRetry: error',data:{tabId,attempt,error:err.message,runtimeError,isContentScriptError},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
if (isContentScriptError && attempt < maxAttempts) {
// Content script not ready yet, retry after delay
console.log(`[BACKGROUND] Content script not ready, retrying in ${retryDelay}ms...`);
@@ -563,9 +354,32 @@ async function cleanupParseRequest(tabId, data, error) {
}
}
+/**
+ * Transform account URL (e.g. /str/topmons) to listing URL with 240 items per page.
+ * Example: https://www.ebay.de/str/topmons?... → https://www.ebay.de/sch/i.html?_ssn=topmons&store_name=topmons&_ipg=240
+ */
+function transformAccountUrlTo240ItemsUrl(accountUrl) {
+ try {
+ const url = new URL(accountUrl);
+ const pathname = url.pathname;
+
+ const strMatch = pathname.match(/\/str\/([^\/\?]+)/);
+ if (!strMatch || !strMatch[1]) {
+ throw new Error("Could not extract account name from URL (expected /str/{name})");
+ }
+
+ const accountName = strMatch[1];
+ const baseUrl = `${url.protocol}//${url.hostname}`;
+ const listingUrl = `${baseUrl}/sch/i.html?_ssn=${encodeURIComponent(accountName)}&store_name=${encodeURIComponent(accountName)}&_ipg=240`;
+ return listingUrl;
+ } catch (e) {
+ throw new Error(`Failed to transform account URL: ${e.message}`);
+ }
+}
+
/**
* Handles eBay product scan request
- * Creates a hidden tab, waits for load, sends parse message to content script
+ * Transforms account URL to listing URL with _ipg=240, creates hidden tab, parses, then loads each item in separate tab.
*/
async function handleScanProductsRequest(url, accountId, sendResponse) {
try {
@@ -575,9 +389,18 @@ async function handleScanProductsRequest(url, accountId, sendResponse) {
return;
}
+ let targetUrl = url;
+ try {
+ targetUrl = transformAccountUrlTo240ItemsUrl(url);
+ console.log("[BACKGROUND] Scan using listing URL (240 items):", targetUrl);
+ } catch (transformErr) {
+ console.warn("[BACKGROUND] URL transform failed, using original URL:", transformErr.message);
+ // Fallback: use original URL (e.g. already /sch/ or non-/str/)
+ }
+
// Create hidden tab
const tab = await chrome.tabs.create({
- url: url,
+ url: targetUrl,
active: false
});
@@ -594,14 +417,14 @@ async function handleScanProductsRequest(url, accountId, sendResponse) {
sendResponse: sendResponse
});
+ currentScanProgress = { percent: 0, phase: "listing", total: 0, current: 0, complete: false };
+
// 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(() => {
sendScanMessageWithRetry(tabId, 0);
@@ -655,8 +478,12 @@ async function sendScanMessageWithRetry(tabId, attempt) {
meta: meta
});
} else {
- // Erfolg: sende items + meta
- handleScanComplete(tabId, { items, meta });
+ if (currentScanProgress) {
+ currentScanProgress.phase = "details";
+ currentScanProgress.total = items.length;
+ currentScanProgress.percent = 10;
+ }
+ await handleScanComplete(tabId, { items, meta });
}
} else {
// Fehler: sende error + meta
@@ -709,11 +536,104 @@ async function sendScanMessageWithRetry(tabId, attempt) {
}
}
+const ITEM_TAB_LOAD_TIMEOUT_MS = 3000;
+
+/**
+ * Opens each item URL in a separate background tab, waits for load, parses detail page
+ * (title, price, currency, category, condition), merges into item, then closes tab.
+ */
+async function loadAndParseEachItemTab(items) {
+ if (!Array.isArray(items) || items.length === 0) return;
+
+ const total = items.length;
+ for (let i = 0; i < total; i++) {
+ const item = items[i];
+ if (!item || !item.url) continue;
+
+ try {
+ const tab = await chrome.tabs.create({
+ url: item.url,
+ active: false
+ });
+
+ await new Promise((resolve) => {
+ const listener = (tabId, changeInfo) => {
+ if (tabId === tab.id && changeInfo.status === "complete") {
+ chrome.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ };
+ chrome.tabs.onUpdated.addListener(listener);
+
+ setTimeout(() => {
+ chrome.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }, ITEM_TAB_LOAD_TIMEOUT_MS);
+ });
+
+ const injected = await ensureContentScriptInjected(tab.id);
+ if (!injected) {
+ console.warn(`[BACKGROUND] Content script not ready in item tab ${i + 1}, skipping detail parse`);
+ }
+
+ try {
+ const response = injected
+ ? await chrome.tabs.sendMessage(tab.id, { action: "PARSE_ITEM_DETAIL" })
+ : null;
+ if (response?.ok && response?.data) {
+ const d = response.data;
+ if (d.title != null && d.title !== "") item.title = d.title;
+ if (d.price != null) item.price = d.price;
+ if (d.currency != null && d.currency !== "") item.currency = d.currency;
+ if (d.category != null && d.category !== "") item.category = d.category;
+ if (d.condition != null && d.condition !== "") item.condition = d.condition;
+ if (d.quantityAvailable != null) item.quantityAvailable = d.quantityAvailable;
+ if (d.quantitySold != null) item.quantitySold = d.quantitySold;
+ if (d.watchCount != null) item.watchCount = d.watchCount;
+ if (d.inCartsCount != null) item.inCartsCount = d.inCartsCount;
+ }
+ } catch (parseErr) {
+ console.warn(`[BACKGROUND] PARSE_ITEM_DETAIL failed for ${item.url}:`, parseErr);
+ }
+
+ if (currentScanProgress && total > 0) {
+ currentScanProgress.current = i + 1;
+ currentScanProgress.percent = Math.min(99, 10 + Math.round((90 * (i + 1)) / total));
+ }
+
+ try {
+ await chrome.tabs.remove(tab.id);
+ } catch (removeErr) {
+ console.warn(`[BACKGROUND] Could not close item tab:`, removeErr);
+ }
+ } catch (e) {
+ console.warn(`[BACKGROUND] Failed to load/parse item tab ${i + 1}/${total}:`, item.url, e);
+ }
+ }
+}
+
/**
* Handles scan complete response from content script
*/
-function handleScanComplete(tabId, data) {
- cleanupScanRequest(tabId, data, null);
+async function handleScanComplete(tabId, data) {
+ const request = activeScanRequests.get(tabId);
+ if (request && request.timeout) {
+ clearTimeout(request.timeout);
+ request.timeout = null;
+ }
+
+ const items = data?.items || [];
+ if (items.length > 0) {
+ await loadAndParseEachItemTab(items);
+ }
+
+ if (currentScanProgress) {
+ currentScanProgress.percent = 100;
+ currentScanProgress.complete = true;
+ currentScanProgress.current = items.length;
+ }
+
+ await cleanupScanRequest(tabId, data, null);
}
/**
@@ -731,6 +651,8 @@ async function cleanupScanRequest(tabId, data, error) {
// Remove from active requests
activeScanRequests.delete(tabId);
+ currentScanProgress = null;
+
// Close tab (always, even on error)
try {
await chrome.tabs.remove(tabId);
diff --git a/Extension/content-script.js b/Extension/content-script.js
index 43113c0..64aa3a3 100644
--- a/Extension/content-script.js
+++ b/Extension/content-script.js
@@ -10,6 +10,10 @@ function setExtensionFlag() {
const hasRuntime = hasChrome && chrome.runtime;
const runtimeId = hasRuntime ? chrome.runtime.id : null;
if (typeof window !== 'undefined' && hasChrome && hasRuntime && runtimeId) {
+ // WICHTIG: Content Scripts haben einen isolierten Context
+ // window.__EBAY_EXTENSION__ wird im Content Script Context gesetzt,
+ // aber die Web-App läuft im Page Context - diese sind getrennt!
+ // Daher verlassen wir uns hauptsächlich auf postMessage
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);
@@ -23,6 +27,8 @@ function setExtensionFlag() {
// Versuche Flag sofort zu setzen
console.log('[ESHIP-CONTENT] Content script loaded');
+console.log('[ESHIP-CONTENT] URL:', window.location.href);
+console.log('[ESHIP-CONTENT] ReadyState:', document.readyState);
if (!setExtensionFlag()) {
// Wenn window nicht verfügbar, warte auf DOMContentLoaded oder document.readyState
if (document.readyState === 'loading') {
@@ -35,34 +41,113 @@ if (!setExtensionFlag()) {
setExtensionFlag();
}, 0);
}
-}
+} else {
+ }
// 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;
+ const hasRuntime = !!chrome.runtime;
+ const hasId = !!runtimeId;
+ const currentUrl = window.location.href;
+
if (runtimeId) {
- // Sende Extension-ID an Web-App
- window.postMessage({
+ const message = {
source: "eship-extension",
type: "EXTENSION_ID",
extensionId: runtimeId
- }, "*");
- }
+ };
+
+ // Sende Extension-ID an Web-App
+ window.postMessage(message, "*");
+
+ } else {
+ }
} catch (e) {
console.error('[ESHIP-CONTENT] Error sending extension ID:', e);
}
}
-// Sende Extension-ID beim Laden
+// Sende Extension-ID sofort beim Laden (wichtig für Seiten-Reload)
sendExtensionIdToWebApp();
-// Auch nach kurzer Verzögerung nochmal (falls Web-App noch nicht bereit ist)
+
+// Sende auch nach kurzen Verzögerungen (falls Web-App noch nicht bereit ist)
+setTimeout(sendExtensionIdToWebApp, 100);
setTimeout(sendExtensionIdToWebApp, 500);
+setTimeout(sendExtensionIdToWebApp, 1000);
+setTimeout(sendExtensionIdToWebApp, 2000);
+
+// Kontinuierlich postMessage senden, damit die Web-App die Extension erkennen kann
+// (auch wenn der User die Extension NACH dem Laden der Seite installiert)
+let extensionAnnounceInterval = setInterval(() => {
+ sendExtensionIdToWebApp();
+}, 2000); // Alle 2 Sekunden senden
+
+// Stoppe das Intervall nach 5 Minuten (um Ressourcen zu sparen, aber lange genug für Onboarding)
+setTimeout(() => {
+ if (extensionAnnounceInterval) {
+ clearInterval(extensionAnnounceInterval);
+ extensionAnnounceInterval = null;
+ }
+}, 300000); // 5 Minuten
window.addEventListener("message", (event) => {
+ // PING_EXTENSION Handler: Web-App fragt aktiv nach Extension
+ // Akzeptiere sowohl "eship-webapp" als auch "eship-webapp-page-context"
+ if ((event.data?.source === MESSAGE_SOURCE || event.data?.source === "eship-webapp-page-context") && event.data?.type === "PING_EXTENSION") {
+ // Verwende console.log als Fallback, da fetch möglicherweise fehlschlägt
+ console.log('[ESHIP-CONTENT] Received PING_EXTENSION, responding...', event.data);
+
+ // Antworte sofort mit Extension-ID
+ const runtimeId = chrome.runtime?.id;
+ console.log('[ESHIP-CONTENT] Runtime ID:', runtimeId);
+
+ if (runtimeId) {
+ const response = {
+ source: "eship-extension",
+ type: "EXTENSION_ID",
+ extensionId: runtimeId,
+ requestId: event.data?.requestId
+ };
+
+ console.log('[ESHIP-CONTENT] Sending response:', response);
+ window.postMessage(response, "*");
+
+ // Setze user_extension_load auf true im Backend
+ // Hole JWT aus Storage und sende an Backend
+ chrome.storage.local.get("auth_jwt").then((data) => {
+ const jwt = data.auth_jwt;
+ if (jwt) {
+ // Backend-Endpoint aufrufen
+ fetch("http://localhost:3000/api/user/set-extension-loaded", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `Bearer ${jwt}`
+ }
+ })
+ .then(res => res.json())
+ .then(result => {
+ console.log('[ESHIP-CONTENT] user_extension_load set to true:', result);
+ })
+ .catch(err => {
+ console.error('[ESHIP-CONTENT] Failed to set user_extension_load:', err);
+ });
+ } else {
+ console.warn('[ESHIP-CONTENT] No JWT found, cannot set user_extension_load');
+ }
+ });
+
+ } else {
+ console.error('[ESHIP-CONTENT] No runtime ID available!');
+ }
+ return;
+ }
+
// Sicherheitscheck: Nur Nachrichten von derselben Origin akzeptieren
- if (event.data?.source !== MESSAGE_SOURCE) return;
+ if (event.data?.source !== MESSAGE_SOURCE && event.data?.source !== "eship-webapp-page-context") return;
// Auth Messages (JWT)
if (event.data.type === "AUTH_JWT" || event.data.type === "AUTH_CLEARED") {
diff --git a/Extension/ebay-content-script.js b/Extension/ebay-content-script.js
index 0e41832..141b39f 100644
--- a/Extension/ebay-content-script.js
+++ b/Extension/ebay-content-script.js
@@ -6,29 +6,15 @@
// Log dass Content Script geladen wurde
console.log("[EBAY-CONTENT] Content script loaded on:", window.location.href);
-// #region agent log
-fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'ebay-content-script.js:7',message:'ebay-content-script: loaded',data:{url:window.location.href,readyState:document.readyState},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
-// #endregion
-
// Message Listener für Parsing-Anfragen
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'ebay-content-script.js:10',message:'ebay-content-script: message received',data:{action:message.action},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
-
// Ping-Handler für Content Script Verfügbarkeitsprüfung
if (message.action === "PING") {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'ebay-content-script.js:13',message:'ebay-content-script: PING handler',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
sendResponse({ ok: true, ready: true });
return true;
}
if (message.action === "PARSE_EBAY") {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'ebay-content-script.js:17',message:'ebay-content-script: PARSE_EBAY handler',data:{readyState:document.readyState},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
// Wrapper um sicherzustellen, dass immer eine Antwort gesendet wird
try {
// Prüfe ob DOM bereit ist
@@ -75,6 +61,17 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
return true; // async response
}
+ if (message.action === "PARSE_ITEM_DETAIL") {
+ try {
+ const detail = parseItemDetailPage();
+ sendResponse({ ok: true, data: detail });
+ } catch (e) {
+ console.warn("[EBAY-CONTENT] PARSE_ITEM_DETAIL error:", e);
+ sendResponse({ ok: true, data: {} });
+ }
+ return true;
+ }
+
if (message.action === "PARSE_PRODUCT_LIST") {
// async function, need to return promise
parseProductList()
@@ -183,6 +180,12 @@ function extractSellerId() {
return strMatch[1].trim();
}
+ // Pattern: _ssn=username (Seller Name Parameter in Suchergebnis-URLs)
+ const ssnMatch = url.match(/[?&]_ssn=([^&]+)/i);
+ if (ssnMatch && ssnMatch[1]) {
+ return decodeURIComponent(ssnMatch[1]).trim();
+ }
+
// Methode 2: DOM-Elemente suchen
// Suche nach verschiedenen Selektoren, die Seller-ID enthalten könnten
const possibleSelectors = [
@@ -683,7 +686,6 @@ async function parseProductList() {
let pageType = detectPageType();
let finalUrl = window.location.href;
let reason = null;
-
try {
// Schritt 1: Warte auf Item-Links (Polling)
let links = await waitForItemLinks(4000, 250, 5);
@@ -768,17 +770,14 @@ async function parseProductList() {
}
}
- // Return max 60 items (first page)
- const result = parsedItems.slice(0, 60);
-
return {
ok: true,
- items: result,
+ items: parsedItems,
meta: {
pageType,
finalUrl,
attempts,
- reason: reason || (result.length > 0 ? "items_found" : "parsed_zero_items")
+ reason: reason || (parsedItems.length > 0 ? "items_found" : "parsed_zero_items")
}
};
@@ -796,66 +795,103 @@ async function parseProductList() {
};
}
}
+
+/**
+ * Parst Produktdetail-Seite (/itm/...) für title, price, currency, category, condition,
+ * quantityAvailable, quantitySold, watchCount, inCartsCount.
+ */
+function parseItemDetailPage() {
+ const out = {
+ title: "",
+ price: null,
+ currency: null,
+ category: null,
+ condition: null,
+ quantityAvailable: null,
+ quantitySold: null,
+ watchCount: null,
+ inCartsCount: null
+ };
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");
+ const titleEl = document.querySelector("[data-testid=\"x-item-title\"] h1 .ux-textspans") ||
+ document.querySelector("h1.x-item-title__mainTitle .ux-textspans");
+ if (titleEl) {
+ out.title = (titleEl.textContent || "").trim().replace(/\s+/g, " ");
+ }
+
+ const priceEl = document.querySelector("[data-testid=\"x-price-primary\"] .ux-textspans");
+ if (priceEl) {
+ const priceText = (priceEl.textContent || "").trim();
+ const parsed = parsePrice(priceText);
+ out.price = parsed.price;
+ out.currency = parsed.currency;
+ }
+
+ const breadcrumbs = document.querySelectorAll("a.seo-breadcrumb-text span");
+ if (breadcrumbs.length > 0) {
+ const parts = [];
+ breadcrumbs.forEach((span) => {
+ const t = (span.textContent || "").trim();
+ if (t) parts.push(t);
+ });
+ out.category = parts.join(" > ");
+ }
+
+ const condEl = document.querySelector("dd.ux-labels-values__values .ux-textspans");
+ if (condEl) {
+ const raw = (condEl.textContent || "").trim();
+ const colonIdx = raw.indexOf(":");
+ out.condition = colonIdx >= 0 ? raw.slice(0, colonIdx).trim() : raw.slice(0, 80);
+ }
+
+ // x-quantity__availability: "9 verfügbar", "8 verkauft"
+ const availEl = document.querySelector(".x-quantity__availability");
+ if (availEl) {
+ const text = (availEl.textContent || "").trim();
+ const verfMatch = text.match(/(\d+)\s*verfügbar/i);
+ if (verfMatch && verfMatch[1]) {
+ const n = parseInt(verfMatch[1], 10);
+ if (!isNaN(n) && n >= 0) out.quantityAvailable = n;
+ }
+ const verkMatch = text.match(/(\d+)\s*verkauft/i);
+ if (verkMatch && verkMatch[1]) {
+ const n = parseInt(verkMatch[1], 10);
+ if (!isNaN(n) && n >= 0) out.quantitySold = n;
+ }
+ }
+
+ // x-watch-heart-btn: .x-watch-heart-btn-text "14" oder aria-label "14 Beobachter"
+ const watchBtn = document.querySelector("button.x-watch-heart-btn");
+ if (watchBtn) {
+ const textEl = watchBtn.querySelector(".x-watch-heart-btn-text");
+ if (textEl) {
+ const n = parseInt((textEl.textContent || "").trim().replace(/\D/g, ""), 10);
+ if (!isNaN(n) && n >= 0) out.watchCount = n;
+ }
+ if (out.watchCount == null) {
+ const label = (watchBtn.getAttribute("aria-label") || "").trim();
+ const m = label.match(/(\d+)\s*Beobachter/i);
+ if (m && m[1]) {
+ const n = parseInt(m[1], 10);
+ if (!isNaN(n) && n >= 0) out.watchCount = n;
}
}
}
-
- // 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);
+
+ // [data-testid="x-ebay-signal"]: "In 8 Warenkörben"
+ const signalEl = document.querySelector("[data-testid=\"x-ebay-signal\"]");
+ if (signalEl) {
+ const text = (signalEl.textContent || "").trim();
+ const m = text.match(/in\s*(\d+)\s*warenkörben/i);
+ if (m && m[1]) {
+ const n = parseInt(m[1], 10);
+ if (!isNaN(n) && n >= 0) out.inCartsCount = n;
}
}
-
- // Return max 60 items (first page)
- return parsedItems.slice(0, 60);
-
- } catch (error) {
- // Re-throw to be caught by message handler
- throw error;
+ } catch (e) {
+ console.warn("[EBAY-CONTENT] parseItemDetailPage error:", e);
}
+ return out;
}
/**
diff --git a/Server/backend/server.js b/Server/backend/server.js
index ac12809..717366d 100644
--- a/Server/backend/server.js
+++ b/Server/backend/server.js
@@ -49,6 +49,41 @@ app.post("/api/action", async (req, res) => {
}
});
+// Endpoint: Setze user_extension_load auf true
+app.post("/api/user/set-extension-loaded", async (req, res) => {
+ try {
+ const auth = req.headers.authorization || "";
+ const jwt = auth.startsWith("Bearer ") ? auth.slice(7) : "";
+ if (!jwt) return res.status(401).json({ ok: false, error: "missing token" });
+
+ // 1) User token validieren
+ const userClient = makeUserClient(jwt);
+ const account = new Account(userClient);
+ const user = await account.get();
+
+ // 2) User-Dokument mit Admin Key aktualisieren
+ const adminClient = makeAdminClient();
+ const db = new Databases(adminClient);
+ const databaseId = process.env.APPWRITE_DATABASE_ID || "eship-db";
+ const usersCollectionId = process.env.APPWRITE_USERS_COLLECTION_ID || "users";
+
+ // Update user document: setze user_extension_load auf true
+ await db.updateDocument(
+ databaseId,
+ usersCollectionId,
+ user.$id,
+ {
+ user_extension_load: true
+ }
+ );
+
+ return res.json({ ok: true, userId: user.$id });
+ } catch (e) {
+ console.error("Error in /api/user/set-extension-loaded:", e);
+ return res.status(401).json({ ok: false, error: "unauthorized" });
+ }
+});
+
app.listen(PORT, () => {
console.log(`Backend server running on port ${PORT}`);
});
diff --git a/Server/package-lock.json b/Server/package-lock.json
index 45a4a69..6a1665f 100644
--- a/Server/package-lock.json
+++ b/Server/package-lock.json
@@ -74,7 +74,6 @@
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/generator": "^7.28.6",
@@ -331,7 +330,6 @@
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
"integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@emotion/memoize": "^0.9.0"
}
@@ -1707,7 +1705,6 @@
"integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -1755,7 +1752,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2031,7 +2027,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -2656,7 +2651,6 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -3191,8 +3185,7 @@
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.14.2.tgz",
"integrity": "sha512-P8/mMxVLU7o4+55+1TCnQrPmgjPKnwkzkXOK1asnR9Jg2lna4tEY5qBJjMmAaOBDDZWtlRjBXjLa0w53G/uBLA==",
- "license": "Standard 'no charge' license: https://gsap.com/standard-license.",
- "peer": true
+ "license": "Standard 'no charge' license: https://gsap.com/standard-license."
},
"node_modules/has-bigints": {
"version": "1.1.0",
@@ -4510,7 +4503,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -4615,7 +4607,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4625,7 +4616,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -5425,7 +5415,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
diff --git a/Server/public/extension.zip b/Server/public/extension.zip
new file mode 100644
index 0000000..51dfd0c
Binary files /dev/null and b/Server/public/extension.zip differ
diff --git a/Server/src/App.jsx b/Server/src/App.jsx
index dda16f8..141aa85 100644
--- a/Server/src/App.jsx
+++ b/Server/src/App.jsx
@@ -18,9 +18,13 @@ import { OnboardingGate } from "./components/onboarding/OnboardingGate";
import { SidebarHeader } from "./components/sidebar/SidebarHeader";
import { useHashRoute } from "./lib/routing";
import { account, databases, databaseId, usersCollectionId } from "./lib/appwrite";
+import { fetchManagedAccounts } from "./services/accountsService";
+import { useScan } from "./context/ScanContext";
+import ScanningLoader from "./components/ui/ScanningLoader";
export default function App() {
const { route, navigate } = useHashRoute();
+ const { scanning, scanProgress } = useScan();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [status, setStatus] = useState({ loading: true, authed: false, error: "" });
@@ -32,8 +36,15 @@ export default function App() {
const [checkingUserDoc, setCheckingUserDoc] = useState(false);
const [onboardingLoading, setOnboardingLoading] = useState(false);
const [onboardingError, setOnboardingError] = useState("");
+ const [userExtensionLoad, setUserExtensionLoad] = useState(null); // null = nicht geprüft, true/false = geprüft
+ const [hasAccounts, setHasAccounts] = useState(false); // true wenn User Accounts hat
- const showGate = !hasUserDoc && !checkingUserDoc && authUser !== null;
+ // Gate soll angezeigt werden, wenn:
+ // 1. User-Dokument nicht existiert ODER
+ // 2. User-Dokument existiert, aber user_extension_load = false UND keine Accounts vorhanden
+ // Gate wird versteckt, wenn:
+ // - User-Dokument existiert UND (user_extension_load = true ODER Accounts vorhanden)
+ const showGate = (!hasUserDoc || (hasUserDoc && userExtensionLoad === false && !hasAccounts)) && !checkingUserDoc && authUser !== null;
async function checkUserDocument(userId) {
if (!databases || !databaseId || !usersCollectionId) {
@@ -66,13 +77,53 @@ export default function App() {
// Prüfe, ob User-Dokument existiert
const userDocExists = await checkUserDocument(user.$id);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:68',message:'refreshAuth: userDocExists check',data:{userId:user.$id,userDocExists},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
setHasUserDoc(userDocExists);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:71',message:'refreshAuth: hasUserDoc set',data:{hasUserDoc:userDocExists,showGateWillBe:!userDocExists && !checkingUserDoc && user !== null},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
+
+ // Prüfe user_extension_load und Accounts, wenn User-Dokument existiert
+ if (userDocExists && databases && databaseId && usersCollectionId) {
+ try {
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, user.$id);
+ const extensionLoad = userDoc?.user_extension_load === true;
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:78',message:'refreshAuth: userDoc retrieved for extension check',data:{userExtensionLoad:userDoc?.user_extension_load,userExtensionLoadType:typeof userDoc?.user_extension_load,userExtensionLoadStrictFalse:userDoc?.user_extension_load === false,extensionLoad},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
+ setUserExtensionLoad(extensionLoad);
+
+ // Prüfe auch Accounts
+ try {
+ const existingAccounts = await fetchManagedAccounts(user.$id);
+ const hasAccountsValue = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+ setHasAccounts(hasAccountsValue);
+ } catch (accountsErr) {
+ setHasAccounts(false);
+ }
+ } catch (docErr) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:82',message:'refreshAuth: error getting userDoc for extension check',data:{error:docErr.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
+ // Bei Fehler: Setze auf null (nicht geprüft)
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
+ } else {
+ // Kein User-Dokument → user_extension_load ist nicht relevant
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
await handoffJwtToExtension();
} catch (e) {
setStatus({ loading: false, authed: false, error: "" });
setAuthUser(null);
setHasUserDoc(false);
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
} finally {
setCheckingUserDoc(false);
}
@@ -94,18 +145,50 @@ export default function App() {
const userDocExists = await checkUserDocument(user.$id);
setHasUserDoc(userDocExists);
+ // Prüfe user_extension_load und Accounts, wenn User-Dokument existiert
+ if (userDocExists && databases && databaseId && usersCollectionId) {
+ try {
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, user.$id);
+ const extensionLoad = userDoc?.user_extension_load === true;
+ setUserExtensionLoad(extensionLoad);
+
+ // Prüfe auch Accounts
+ try {
+ const existingAccounts = await fetchManagedAccounts(user.$id);
+ const hasAccountsValue = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+ setHasAccounts(hasAccountsValue);
+ } catch (accountsErr) {
+ setHasAccounts(false);
+ }
+ } catch (docErr) {
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
+ } else {
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
+
await handoffJwtToExtension();
} catch (e) {
setStatus({ loading: false, authed: false, error: "Login fehlgeschlagen" });
setAuthUser(null);
setHasUserDoc(false);
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
} finally {
setCheckingUserDoc(false);
}
}
async function handleOnboardingStart() {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:162',message:'handleOnboardingStart: entry',data:{hasAuthUser:!!authUser,hasDatabases:!!databases,hasDatabaseId:!!databaseId,hasUsersCollectionId:!!usersCollectionId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
if (!authUser || !databases || !databaseId || !usersCollectionId) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:165',message:'handleOnboardingStart: configuration incomplete',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
setOnboardingError("Fehler: Konfiguration unvollständig");
return;
}
@@ -114,38 +197,147 @@ export default function App() {
setOnboardingError("");
try {
- await databases.createDocument(
- databaseId,
- usersCollectionId,
- authUser.$id, // Document-ID = Auth-User-ID
- {
- user_name: authUser.name || "User"
- }
- );
-
- // Erfolg: User-Dokument erstellt
- setHasUserDoc(true);
- setOnboardingError("");
- } catch (e) {
- // 409 Conflict bedeutet, dass das Dokument bereits existiert
- // Das ist ok, da wir idempotent sein wollen
- if (e.code === 409 || e.type === 'document_already_exists') {
- setHasUserDoc(true);
- setOnboardingError("");
- } else if (e.code === 401 || e.type === 'general_unauthorized_scope') {
- // 401 Unauthorized: Permissions nicht richtig gesetzt
- setOnboardingError(
- "Berechtigung verweigert. Bitte prüfe in Appwrite, ob die users Collection die richtigen Permissions hat. " +
- "Siehe setup/USERS_COLLECTION_SETUP.md für Details."
- );
- } else {
- // Andere Fehler anzeigen
- setOnboardingError(e.message || "Fehler beim Erstellen des Profils. Bitte versuche es erneut.");
+ // Prüfe zuerst, ob User-Dokument bereits existiert
+ let userDocExists = false;
+ try {
+ await databases.getDocument(databaseId, usersCollectionId, authUser.$id);
+ userDocExists = true;
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:178',message:'handleOnboardingStart: userDoc exists',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ } catch (e) {
+ // Dokument existiert nicht - wird erstellt
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:182',message:'handleOnboardingStart: userDoc does not exist, will create',data:{error:e.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ }
+
+ if (!userDocExists) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:187',message:'handleOnboardingStart: creating userDoc',data:{userId:authUser.$id},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ await databases.createDocument(
+ databaseId,
+ usersCollectionId,
+ authUser.$id, // Document-ID = Auth-User-ID
+ {
+ user_name: authUser.name || "User",
+ user_extension_load: false
+ }
+ );
+ // Erfolg: User-Dokument erstellt
+ setHasUserDoc(true);
+ // user_extension_load ist false beim Erstellen (siehe payload)
+ setUserExtensionLoad(false);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:202',message:'handleOnboardingStart: userDoc created, setting hasUserDoc=true',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+
+ // Prüfe, ob User bereits Accounts hat (nach dem Erstellen des User-Dokuments)
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:207',message:'handleOnboardingStart: checking for accounts after userDoc creation',data:{userId:authUser.$id},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ try {
+ const existingAccounts = await fetchManagedAccounts(authUser.$id);
+ const hasAccountsValue = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+ setHasAccounts(hasAccountsValue);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:212',message:'handleOnboardingStart: accounts check result after creation',data:{hasAccounts:hasAccountsValue,accountsCount:existingAccounts?.length || 0},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ } catch (accountsErr) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:216',message:'handleOnboardingStart: error checking accounts after creation',data:{error:accountsErr.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ setHasAccounts(false);
+ }
+ } else {
+ // Dokument existiert bereits - prüfe user_extension_load
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:206',message:'handleOnboardingStart: userDoc exists, checking extension load',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, authUser.$id);
+ const extensionLoad = userDoc?.user_extension_load === true;
+ setHasUserDoc(true);
+ setUserExtensionLoad(extensionLoad);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:212',message:'handleOnboardingStart: userDoc retrieved, setting hasUserDoc=true',data:{extensionLoad},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ }
+
+ // Prüfe, ob User Accounts hat (nach dem Erstellen/Prüfen des User-Dokuments)
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:217',message:'handleOnboardingStart: checking for accounts',data:{userId:authUser.$id},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ try {
+ const existingAccounts = await fetchManagedAccounts(authUser.$id);
+ const hasAccountsValue = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+ setHasAccounts(hasAccountsValue);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:222',message:'handleOnboardingStart: accounts check result',data:{hasAccounts:hasAccountsValue,accountsCount:existingAccounts?.length || 0},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ } catch (accountsErr) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:226',message:'handleOnboardingStart: error checking accounts',data:{error:accountsErr.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ setHasAccounts(false);
+ }
+
+ setOnboardingError("");
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:232',message:'handleOnboardingStart: success, showGate will be',data:{hasUserDoc:true,userExtensionLoad,hasAccounts,showGateWillBe:(hasUserDoc && userExtensionLoad === false && !hasAccounts)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ } catch (e) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:220',message:'handleOnboardingStart: error caught',data:{errorCode:e.code,errorType:e.type,errorMessage:e.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ // 409 Conflict bedeutet, dass das Dokument bereits existiert
+ // Das ist ok, da wir idempotent sein wollen
+ if (e.code === 409 || e.type === 'document_already_exists') {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:225',message:'handleOnboardingStart: document already exists (409)',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ setHasUserDoc(true);
+ // Prüfe user_extension_load für existierendes Dokument
+ if (authUser && databases && databaseId && usersCollectionId) {
+ try {
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, authUser.$id);
+ const extensionLoad = userDoc?.user_extension_load === true;
+ setUserExtensionLoad(extensionLoad);
+
+ // Prüfe auch Accounts
+ try {
+ const existingAccounts = await fetchManagedAccounts(authUser.$id);
+ const hasAccountsValue = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+ setHasAccounts(hasAccountsValue);
+ } catch (accountsErr) {
+ setHasAccounts(false);
+ }
+ } catch (docErr) {
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
+ } else {
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ }
+ setOnboardingError("");
+ } else if (e.code === 401 || e.type === 'general_unauthorized_scope') {
+ // 401 Unauthorized: Permissions nicht richtig gesetzt
+ setOnboardingError(
+ "Berechtigung verweigert. Bitte prüfe in Appwrite, ob die users Collection die richtigen Permissions hat. " +
+ "Siehe setup/USERS_COLLECTION_SETUP.md für Details."
+ );
+ } else {
+ // Andere Fehler anzeigen
+ setOnboardingError(e.message || "Fehler beim Erstellen des Profils. Bitte versuche es erneut.");
+ }
+ } finally {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'App.jsx:245',message:'handleOnboardingStart: finally, setting loading=false',data:{hasUserDoc,userExtensionLoad,showGateWillBe:(!hasUserDoc || (hasUserDoc && userExtensionLoad === false)) && !checkingUserDoc && authUser !== null},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ setOnboardingLoading(false);
}
- } finally {
- setOnboardingLoading(false);
}
- }
async function logout() {
setStatus((s) => ({ ...s, loading: true, error: "" }));
@@ -153,9 +345,11 @@ export default function App() {
await account.deleteSession("current");
} catch {}
setStatus({ loading: false, authed: false, error: "" });
- setAuthUser(null);
- setHasUserDoc(false);
- setOnboardingError("");
+ setAuthUser(null);
+ setHasUserDoc(false);
+ setUserExtensionLoad(null);
+ setHasAccounts(false);
+ setOnboardingError("");
// Extension informieren: Token weg
sendToExtension({ type: "AUTH_CLEARED" });
@@ -202,6 +396,7 @@ export default function App() {
icon: (
),
+ disabled: scanning,
onClick: (e) => {
e.preventDefault();
navigate("/accounts");
@@ -288,6 +483,7 @@ export default function App() {
onStart={handleOnboardingStart}
loading={onboardingLoading}
error={onboardingError}
+ initialPhase={userExtensionLoad === false ? "extension" : "welcome"}
/>
)}
@@ -297,26 +493,31 @@ export default function App() {
"flex w-full flex-1 flex-col overflow-hidden rounded-md border border-neutral-200 bg-gray-100 md:flex-row dark:border-neutral-700 dark:bg-neutral-800",
"h-screen relative z-10"
)}>
-
-
-
-
-
- {links.map((link, idx) => (
-
- ))}
+ {!scanning && (
+
+
+
+
+
+ {links.map((link, idx) => (
+
+ ))}
+
-
-
- {
- e.preventDefault();
- logout();
- }} />
-
-
-
+
+ {
+ e.preventDefault();
+ logout();
+ }} />
+
+
+
+ )}
{renderContent()}
+ {scanning && (
+
+ )}
>
)}
diff --git a/Server/src/components/dashboard/sections/ProductsSection.jsx b/Server/src/components/dashboard/sections/ProductsSection.jsx
index e2ee43b..36cf0b7 100644
--- a/Server/src/components/dashboard/sections/ProductsSection.jsx
+++ b/Server/src/components/dashboard/sections/ProductsSection.jsx
@@ -1,12 +1,16 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useRef } from "react";
import { DataTable } from "../ui/DataTable";
import { Pagination } from "../ui/Pagination";
import { Filters } from "../ui/Filters";
import { cn } from "../../../lib/utils";
import { getProductsPage, getProductPreview } from "../../../services/dashboardService";
import { scanProductsForAccount } from "../../../services/productsService";
+import { getScanProgress } from "../../../services/ebayParserService";
+import { useScan } from "../../../context/ScanContext";
import { AnimatePresence, motion } from "motion/react";
+const SCAN_POLL_MS = 300;
+
export const ProductsSection = ({ onJumpToSection, activeAccountId }) => {
const [statusFilter, setStatusFilter] = useState("all");
const [searchQuery, setSearchQuery] = useState("");
@@ -18,8 +22,9 @@ export const ProductsSection = ({ onJumpToSection, activeAccountId }) => {
const [total, setTotal] = useState(0);
const [selectedProduct, setSelectedProduct] = useState(null);
const [previewLoading, setPreviewLoading] = useState(false);
- const [scanning, setScanning] = useState(false);
const [scanToast, setScanToast] = useState({ show: false, message: "", type: "success" });
+ const pollRef = useRef(null);
+ const { scanning, startScan, endScan, updateProgress } = useScan();
// Lade Products wenn activeAccountId oder Filter sich ändern
useEffect(() => {
@@ -121,17 +126,39 @@ export const ProductsSection = ({ onJumpToSection, activeAccountId }) => {
return;
}
- setScanning(true);
setError(null);
+ startScan();
+
+ const stopPolling = () => {
+ if (pollRef.current) {
+ clearInterval(pollRef.current);
+ pollRef.current = null;
+ }
+ };
+
+ pollRef.current = setInterval(async () => {
+ try {
+ const p = await getScanProgress();
+ if (p && (p.percent != null || p.phase || p.complete)) {
+ updateProgress({
+ percent: p.percent ?? 0,
+ phase: p.phase ?? "idle",
+ total: p.total ?? 0,
+ current: p.current ?? 0,
+ complete: !!p.complete,
+ });
+ }
+ } catch {
+ // ignore
+ }
+ }, SCAN_POLL_MS);
try {
- // Führe Scan aus
const result = await scanProductsForAccount(activeAccountId);
+ stopPolling();
- // Refresh Products-Liste
await loadProducts();
- // Zeige Erfolgs-Toast
const updated = result.updated ?? 0;
setScanToast({
show: true,
@@ -142,23 +169,45 @@ export const ProductsSection = ({ onJumpToSection, activeAccountId }) => {
setScanToast({ show: false, message: "", type: "success" });
}, 3000);
} catch (e) {
+ stopPolling();
console.error("Fehler beim Scannen der Produkte:", e);
-
- // Logge meta für Dev-Debugging
+
const meta = e.meta || {};
if (Object.keys(meta).length > 0) {
console.log("[scan meta]", meta);
}
-
- // Prüfe auf no_items_found oder empty_items
+
const errorMsg = e.message || "Fehler beim Scannen der Produkte";
const isNoItems = errorMsg.includes("no_items_found") || errorMsg.includes("empty_items");
-
- // Zeige Toast mit spezifischer Meldung für 0 Items
- const toastMessage = isNoItems
- ? "0 Produkte gefunden. Bitte pruefe, ob die URL auf den Shop/Artikel-Bereich des Sellers zeigt."
- : errorMsg;
-
+ const isParsingFailed = errorMsg.includes("Parsing failed");
+
+ let toastMessage = errorMsg;
+ if (isNoItems) {
+ toastMessage = "0 Produkte gefunden. Bitte prüfe, ob die URL auf den Shop/Artikel-Bereich des Sellers zeigt.";
+ } else if (isParsingFailed) {
+ toastMessage = "Extension konnte keine Produkte finden. ";
+ if (meta.pageType && meta.pageType !== "unknown") {
+ toastMessage += `Seitentyp: ${meta.pageType}. `;
+ }
+ if (meta.reason) {
+ toastMessage += `Grund: ${meta.reason}. `;
+ }
+ if (meta.finalUrl) {
+ toastMessage += `URL: ${meta.finalUrl}`;
+ }
+ if (!meta.pageType && !meta.reason && !meta.finalUrl) {
+ toastMessage += "Bitte stelle sicher, dass die Account-URL auf eine Seite mit Produkt-Listings zeigt (z.B. Storefront oder Seller-Listings).";
+ }
+ } else if (e.meta) {
+ const m = e.meta;
+ if (m.pageType && m.pageType !== "unknown") {
+ toastMessage += ` (Seitentyp: ${m.pageType})`;
+ }
+ if (m.reason) {
+ toastMessage += ` (${m.reason})`;
+ }
+ }
+
setScanToast({
show: true,
message: toastMessage,
@@ -166,9 +215,13 @@ export const ProductsSection = ({ onJumpToSection, activeAccountId }) => {
});
setTimeout(() => {
setScanToast({ show: false, message: "", type: "success" });
- }, 3000);
+ }, 5000);
} finally {
- setScanning(false);
+ if (pollRef.current) {
+ clearInterval(pollRef.current);
+ pollRef.current = null;
+ }
+ endScan();
}
};
diff --git a/Server/src/components/onboarding/OnboardingGate.jsx b/Server/src/components/onboarding/OnboardingGate.jsx
index c311c75..f2f923e 100644
--- a/Server/src/components/onboarding/OnboardingGate.jsx
+++ b/Server/src/components/onboarding/OnboardingGate.jsx
@@ -1,6 +1,7 @@
"use client";
-import React, { useState } from "react";
+import React, { useState, useEffect, useRef } from "react";
import { motion, AnimatePresence } from "motion/react";
+import styled from "styled-components";
import { BackgroundRippleEffect } from "@/components/layout/BackgroundRippleEffect";
import Shuffle from "@/components/ui/Shuffle";
import ColourfulText from "@/components/ui/colourful-text";
@@ -10,14 +11,178 @@ import { IPhoneNotification } from "@/components/ui/iphone-notification";
import { parseEbayAccount } from "@/services/ebayParserService";
import { createManagedAccount, fetchManagedAccounts } from "@/services/accountsService";
import { account, databases, databaseId, usersCollectionId } from "@/lib/appwrite";
+import { DottedGlowBackground } from "@/components/ui/dotted-glow-background";
-export const OnboardingGate = ({ userName, onStart, loading, error }) => {
- const [phase, setPhase] = useState("shuffle");
+const StyledDownloadButton = styled.div`
+ .button {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 5.3em;
+ height: 5.3em;
+ border: none;
+ cursor: pointer;
+ border-radius: 0.4em;
+ background: rgba(66, 67, 67, 0.6);
+ text-decoration: none;
+ }
+
+ .container {
+ position: relative;
+ width: 3.5em;
+ height: 3.1em;
+ background: none;
+ overflow: hidden;
+ }
+
+ .folder {
+ content: "";
+ position: absolute;
+ }
+
+ .folder_one {
+ bottom: 0;
+ width: 100%;
+ height: 88%;
+ border-radius: 3px;
+ border-top: 2px solid rgb(206, 167, 39);
+ background: linear-gradient(-35deg, rgb(238, 194, 47) 5%, rgb(255, 223, 118));
+ }
+
+ .folder_two {
+ top: 5%;
+ width: 38%;
+ height: 19%;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ background-color: rgb(206, 167, 39);
+ box-shadow: 0 1px 5px -2px rgba(0, 0, 0, 0.5);
+ }
+
+ .folder_two::before {
+ content: "";
+ position: absolute;
+ display: inline;
+ left: 88%;
+ width: 0;
+ height: 0;
+ border-left: 7px solid rgb(206, 167, 39);
+ border-top: 0.3em solid transparent;
+ border-bottom: 0.3em solid transparent;
+ }
+
+ .folder_three {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ left: 0.5em;
+ bottom: 0;
+ width: 2.5em;
+ height: 0.9em;
+ border-radius: 4px 4px 0 0;
+ background: linear-gradient(-35deg, rgb(25, 102, 218), rgb(109, 165, 249));
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
+ }
+
+ .folder_four {
+ left: 1em;
+ bottom: 0.3em;
+ width: 1.5em;
+ height: 0.18em;
+ border-radius: 1em;
+ background-color: rgb(20, 77, 163);
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+ }
+
+ .active_line {
+ content: "";
+ position: absolute;
+ bottom: 0;
+ width: 0.9em;
+ height: 0.4em;
+ background-color: #999;
+ border: none;
+ border-radius: 1em;
+ transition: all 0.15s linear;
+ }
+
+ .button:active .active_line,
+ .button:focus .active_line {
+ width: 2.3em;
+ background-color: rgb(41, 126, 255);
+ }
+
+ .button:focus .container {
+ animation: wow 1s forwards;
+ }
+
+ @keyframes wow {
+ 20% {
+ scale: 0.8;
+ }
+
+ 30% {
+ scale: 1;
+ transform: translateY(0);
+ }
+
+ 50% {
+ transform: translateY(-6px);
+ }
+
+ 65% {
+ transform: translateY(4px);
+ }
+
+ 80% {
+ transform: translateY(0);
+ }
+
+ 100% {
+ scale: 1;
+ }
+ }
+
+ .text {
+ content: "";
+ position: absolute;
+ top: -4.5em;
+ width: 7.7em;
+ height: 2.6em;
+ background-color: #666;
+ color: #fff;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: none;
+ border-radius: 5px;
+ text-shadow: 0 0 10px rgb(0, 0, 0);
+ opacity: 0;
+ transition: all 0.25s linear;
+ font-size: 0.7em;
+ white-space: nowrap;
+ padding: 0 0.5em;
+ }
+
+ .button:hover .text {
+ opacity: 1;
+ }
+`;
+
+export const OnboardingGate = ({ userName, onStart, loading, error, initialPhase = "welcome" }) => {
+ const [phase, setPhase] = useState(initialPhase);
const [submitting, setSubmitting] = useState(false);
const [submitError, setSubmitError] = useState("");
const [showNotification, setShowNotification] = useState(false);
const [notificationMessage, setNotificationMessage] = useState("bitte eine gueltige url verwenden!");
const [skipHovered, setSkipHovered] = useState(false);
+ const [extensionDetected, setExtensionDetected] = useState(false);
+ const extensionCheckIntervalRef = useRef(null);
+ const [showManualContinue, setShowManualContinue] = useState(false);
+ const [extensionDownloaded, setExtensionDownloaded] = useState(false);
+ const [userExtensionLoaded, setUserExtensionLoaded] = useState(false);
const loadingStates = [
{ text: "URL wird verarbeitet..." },
@@ -32,9 +197,320 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
"Paste deine eBay Shop-URL hier...",
];
+ // PostMessage Listener - MUSS IMMER aktiv sein (nicht nur in extension Phase)
+ // damit wir auch Nachrichten empfangen, wenn Extension nach dem Laden installiert wird
+ useEffect(() => {
+ const handleMessage = (event) => {
+ if (event.data?.source === "eship-extension" && event.data?.type === "EXTENSION_ID") {
+ setExtensionDetected(true);
+ return true;
+ }
+ return false;
+ };
+
+ // Registriere Listener IMMER (nicht nur in extension Phase)
+ window.addEventListener("message", handleMessage);
+
+ // Sende sofort mehrere Anfragen beim Mount (falls Extension bereits geladen ist)
+ // Wichtig: Mehrfach senden, da Timing variieren kann
+ const sendPing = () => {
+ window.postMessage({
+ source: "eship-webapp",
+ type: "PING_EXTENSION",
+ requestId: Date.now()
+ }, "*");
+ };
+
+ // Sofort, dann nach kurzen Verzögerungen (für verschiedene Timing-Szenarien)
+ sendPing();
+ setTimeout(sendPing, 100);
+ setTimeout(sendPing, 500);
+ setTimeout(sendPing, 1000);
+ setTimeout(sendPing, 2000);
+
+ return () => {
+ window.removeEventListener("message", handleMessage);
+ };
+ }, []); // Nur einmal beim Mount - Listener bleibt für die gesamte Lebensdauer aktiv
+
+ // Extension-Erkennung: Prüfe window.__EBAY_EXTENSION__ und postMessage
+ useEffect(() => {
+ if (phase !== "extension") return;
+
+ // Prüfe sofort, ob Extension bereits verfügbar ist
+ const checkExtension = () => {
+ const hasWindow = typeof window !== 'undefined';
+ const ebayExtension = hasWindow ? window.__EBAY_EXTENSION__ : undefined;
+ const isDetected = hasWindow && ebayExtension === true;
+
+ if (isDetected) {
+ setExtensionDetected(true);
+ return true;
+ }
+ return false;
+ };
+
+ // Zusätzlicher Listener nur für die extension Phase (für zusätzliche PING-Anfragen)
+ // Der globale Listener oben ist bereits aktiv, aber hier senden wir aktive Anfragen
+
+ // Aktive Suche: Sende postMessage an Extension und bitte um Antwort
+ const requestExtensionId = () => {
+ // Sende eine Nachricht, die der Content Script erkennen sollte
+ // Der Content Script sollte darauf antworten
+ window.postMessage({
+ source: "eship-webapp",
+ type: "PING_EXTENSION",
+ requestId: Date.now()
+ }, "*");
+
+ // Zusätzlich: Injiziere ein Script in den Page Context, das nach der Extension sucht
+ // Dies funktioniert nur, wenn wir Zugriff auf chrome.runtime haben (was wir nicht haben)
+ // Stattdessen: Prüfe, ob ein Script-Tag mit Extension-Marker existiert
+ try {
+ // Erstelle ein temporäres Script-Element, das postMessage sendet
+ const script = document.createElement('script');
+ script.textContent = `
+ (function() {
+ // Prüfe, ob chrome.runtime verfügbar ist (nur im Content Script Context)
+ // Da wir im Page Context sind, können wir das nicht direkt prüfen
+ // Aber wir können postMessage senden und hoffen, dass der Content Script antwortet
+ window.postMessage({
+ source: "eship-webapp-page-context",
+ type: "PING_EXTENSION",
+ requestId: ${Date.now()}
+ }, "*");
+ })();
+ `;
+ document.documentElement.appendChild(script);
+ document.documentElement.removeChild(script);
+ } catch (e) {
+ // Script injection failed - ignore
+ }
+ };
+
+ // Prüfe sofort
+ const immediateCheck = checkExtension();
+
+ if (immediateCheck) {
+ return;
+ }
+
+ // Der globale Listener ist bereits aktiv (siehe useEffect oben)
+ // Hier starten wir nur das aktive Polling für die extension Phase
+
+ // Aktive Suche: Sende sofort eine Anfrage
+ requestExtensionId();
+
+ // Polling-Mechanismus: Prüfe alle 500ms UND sende alle 2 Sekunden eine Anfrage
+ extensionCheckIntervalRef.current = setInterval(() => {
+ if (checkExtension()) {
+ if (extensionCheckIntervalRef.current) {
+ clearInterval(extensionCheckIntervalRef.current);
+ extensionCheckIntervalRef.current = null;
+ }
+ }
+ }, 500);
+
+ // Aktive Suche: Sende alle 2 Sekunden eine Anfrage an die Extension
+ const requestInterval = setInterval(() => {
+ if (!extensionDetected) {
+ requestExtensionId();
+ } else {
+ clearInterval(requestInterval);
+ }
+ }, 2000);
+
+ // Cleanup für requestInterval
+ const cleanupRequestInterval = () => {
+ clearInterval(requestInterval);
+ };
+
+ // Cleanup
+ return () => {
+ // NICHT window.removeEventListener hier - der globale Listener muss aktiv bleiben!
+ if (extensionCheckIntervalRef.current) {
+ clearInterval(extensionCheckIntervalRef.current);
+ extensionCheckIntervalRef.current = null;
+ }
+ cleanupRequestInterval();
+ };
+ }, [phase]);
+
+ // Prüfe beim Mount, ob user_extension_load bereits true ist (nach Reload)
+ useEffect(() => {
+ const checkUserExtensionLoaded = async () => {
+ try {
+ const authUser = await account.get();
+ if (authUser && databases && databaseId && usersCollectionId) {
+ try {
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, authUser.$id);
+ if (userDoc.user_extension_load === true) {
+ setUserExtensionLoaded(true);
+
+ // Prüfe, ob User bereits Accounts hat
+ try {
+ const existingAccounts = await fetchManagedAccounts(authUser.$id);
+
+ // Debug: Log in Browser-Konsole
+ console.log("[OnboardingGate] checkUserExtensionLoaded: Accounts-Prüfung", {
+ userId: authUser.$id,
+ accountsArray: existingAccounts,
+ accountsCount: Array.isArray(existingAccounts) ? existingAccounts.length : 0,
+ hasAccounts: Array.isArray(existingAccounts) && existingAccounts.length > 0
+ });
+
+ // Prüfe explizit: Ist es ein Array und hat es Einträge?
+ const hasAccounts = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+
+ if (hasAccounts) {
+ // User hat bereits Accounts → direkt zum Dashboard
+ console.log("[OnboardingGate] checkUserExtensionLoaded: Accounts gefunden, rufe onStart() auf", {
+ accountsCount: existingAccounts.length
+ });
+ if (onStart) {
+ onStart();
+ }
+ } else {
+ // User hat keine Accounts → zur Input-Phase
+ console.log("[OnboardingGate] checkUserExtensionLoaded: KEINE Accounts gefunden, wechsle zur Input-Phase", {
+ accountsCount: Array.isArray(existingAccounts) ? existingAccounts.length : 0,
+ currentPhase: phase
+ });
+ // Wechsle zur Input-Phase, unabhängig von der aktuellen Phase
+ setTimeout(() => {
+ setPhase("input");
+ }, 1000);
+ }
+ } catch (accountsErr) {
+ // Fehler beim Laden der Accounts → zur Input-Phase
+ console.warn("Fehler beim Laden der Accounts:", accountsErr);
+ setTimeout(() => {
+ setPhase("input");
+ }, 1000);
+ }
+ } else if (userDoc.user_extension_load === false) {
+ // User hat Extension noch nicht geladen → zur Extension-Phase (sofort, ohne Delay)
+ console.log("[OnboardingGate] checkUserExtensionLoaded: user_extension_load ist false, wechsle zur Extension-Phase", {
+ currentPhase: phase
+ });
+ if (phase !== "extension") {
+ // Setze Phase sofort, ohne Delay
+ setPhase("extension");
+ }
+ }
+ } catch (e) {
+ // Dokument existiert nicht oder Fehler - ignorieren
+ }
+ }
+ } catch (err) {
+ // User nicht eingeloggt oder Fehler - ignorieren
+ }
+ };
+
+ checkUserExtensionLoaded();
+ }, []); // Nur einmal beim Mount
+
+ // Prüfe kontinuierlich, ob user_extension_load true wurde (während extension Phase)
+ useEffect(() => {
+ if (phase !== "extension" || userExtensionLoaded) return;
+
+ const checkInterval = setInterval(async () => {
+ try {
+ const authUser = await account.get();
+ if (authUser && databases && databaseId && usersCollectionId) {
+ try {
+ const userDoc = await databases.getDocument(databaseId, usersCollectionId, authUser.$id);
+ if (userDoc.user_extension_load === true) {
+ setUserExtensionLoaded(true);
+
+ // Prüfe, ob User bereits Accounts hat
+ try {
+ const existingAccounts = await fetchManagedAccounts(authUser.$id);
+
+ // Debug: Log in Browser-Konsole
+ console.log("[OnboardingGate] checkInterval: Accounts-Prüfung", {
+ userId: authUser.$id,
+ accountsArray: existingAccounts,
+ accountsCount: Array.isArray(existingAccounts) ? existingAccounts.length : 0,
+ hasAccounts: Array.isArray(existingAccounts) && existingAccounts.length > 0
+ });
+
+ // Prüfe explizit: Ist es ein Array und hat es Einträge?
+ const hasAccounts = Array.isArray(existingAccounts) && existingAccounts.length > 0;
+
+ if (hasAccounts) {
+ // User hat bereits Accounts → direkt zum Dashboard
+ console.log("[OnboardingGate] checkInterval: Accounts gefunden, rufe onStart() auf", {
+ accountsCount: existingAccounts.length
+ });
+ // Interval stoppen, bevor onStart() aufgerufen wird
+ clearInterval(checkInterval);
+ if (onStart) {
+ onStart();
+ }
+ } else {
+ // User hat keine Accounts → zur Input-Phase
+ console.log("[OnboardingGate] checkInterval: KEINE Accounts gefunden, wechsle zur Input-Phase", {
+ accountsCount: Array.isArray(existingAccounts) ? existingAccounts.length : 0
+ });
+ // Interval stoppen, bevor zur Input-Phase gewechselt wird
+ clearInterval(checkInterval);
+ setTimeout(() => {
+ setPhase("input");
+ }, 1000);
+ }
+ } catch (accountsErr) {
+ // Fehler beim Laden der Accounts → zur Input-Phase
+ console.warn("Fehler beim Laden der Accounts:", accountsErr);
+ // Interval stoppen bei Fehler
+ clearInterval(checkInterval);
+ setTimeout(() => {
+ setPhase("input");
+ }, 1000);
+ }
+ }
+ } catch (e) {
+ // Dokument existiert nicht oder Fehler - ignorieren
+ }
+ }
+ } catch (err) {
+ // User nicht eingeloggt oder Fehler - ignorieren
+ }
+ }, 2000); // Alle 2 Sekunden prüfen
+
+ return () => clearInterval(checkInterval);
+ }, [phase, userExtensionLoaded, onStart]);
+
+ // Zeige manuellen "Weiter"-Button nach 10 Sekunden, wenn Extension nicht erkannt wurde
+ useEffect(() => {
+ if (phase === "extension" && !extensionDetected && !userExtensionLoaded) {
+ const timer = setTimeout(() => {
+ setShowManualContinue(true);
+ }, 10000); // 10 Sekunden
+ return () => clearTimeout(timer);
+ } else {
+ setShowManualContinue(false);
+ }
+ }, [phase, extensionDetected, userExtensionLoaded]);
+
+ // Automatischer Übergang zu "input" Phase, wenn Extension erkannt wurde
+ useEffect(() => {
+ if (phase === "extension" && extensionDetected) {
+ // Warte 1-2 Sekunden, dann wechsle zur input Phase
+ const timer = setTimeout(() => {
+ setPhase("input");
+ }, 1500);
+ return () => clearTimeout(timer);
+ }
+ }, [phase, extensionDetected]);
+
+ const handleManualContinue = () => {
+ setPhase("input");
+ };
+
const handleOverlayClick = async (e) => {
- // Only handle clicks on the overlay itself or when in shuffle phase
- if (phase === "shuffle") {
+ // Only handle clicks on the overlay itself or when in welcome phase
+ if (phase === "welcome") {
// Create user document first (but don't call onStart, as that would hide the gate)
// We need to create it directly to ensure it exists for account creation later
try {
@@ -46,7 +522,8 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
usersCollectionId,
authUser.$id,
{
- user_name: authUser.name || "User"
+ user_name: authUser.name || "User",
+ user_extension_load: false
}
);
} catch (docErr) {
@@ -64,7 +541,7 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
// Add small delay to let the shuffle exit animation complete
// Exit animation is 0.5s, so we wait a bit longer to see it fully
setTimeout(() => {
- setPhase("input");
+ setPhase("extension");
}, 600); // 600ms delay - slightly longer than exit animation (500ms)
}
};
@@ -79,14 +556,7 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
// Validate eBay URL
const isValidEbayUrl = (url) => {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:45',message:'isValidEbayUrl: entry',data:{url,hasUrl:!!url,trimmedUrl:url?.trim()},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
if (!url || !url.trim()) {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:48',message:'isValidEbayUrl: empty url',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
return false;
}
@@ -98,16 +568,9 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
const hostname = urlObj.hostname;
const patternMatches = ebayHostnamePattern.test(hostname);
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:62',message:'isValidEbayUrl: validation result',data:{url,hostname,patternMatches,pattern:ebayHostnamePattern.toString()},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
-
return patternMatches;
} catch (e) {
// Invalid URL format
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:62',message:'isValidEbayUrl: URL parse error',data:{url,error:e.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
- // #endregion
return false;
}
};
@@ -116,12 +579,12 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
e.preventDefault();
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:59',message:'handleAccountSubmit: entry',data:{url,hasUrl:!!url,phase},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:418',message:'handleAccountSubmit: entry',data:{url,hasUrl:!!url,phase},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
if (!url || !url.trim()) {
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:64',message:'handleAccountSubmit: empty url, showing notification',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:422',message:'handleAccountSubmit: empty url',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
setNotificationMessage("bitte eine gueltige url verwenden!");
setShowNotification(true);
@@ -131,12 +594,12 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
// Validate eBay URL
const isValid = isValidEbayUrl(url);
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:71',message:'handleAccountSubmit: validation result',data:{url,isValid},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:430',message:'handleAccountSubmit: validation result',data:{url,isValid},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
if (!isValid) {
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:76',message:'handleAccountSubmit: invalid url, showing notification',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:434',message:'handleAccountSubmit: invalid url',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
setNotificationMessage("bitte eine gueltige url verwenden!");
setShowNotification(true);
@@ -149,30 +612,46 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
// Wait 2 seconds for vanish animation, then switch to loading phase
setTimeout(async () => {
// Switch to loading phase first
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:444',message:'handleAccountSubmit: switching to loading phase',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H4'})}).catch(()=>{});
+ // #endregion
setPhase("loading");
try {
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:88',message:'handleAccountSubmit: before parseEbayAccount',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
- // #endregion
-
// Parse eBay account
- const accountData = await parseEbayAccount(url);
-
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:93',message:'handleAccountSubmit: parseEbayAccount success',data:{url,hasAccountData:!!accountData,market:accountData?.market,sellerId:accountData?.sellerId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:449',message:'handleAccountSubmit: before parseEbayAccount',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
+ const accountData = await parseEbayAccount(url);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:452',message:'handleAccountSubmit: parseEbayAccount success',data:{url,hasAccountData:!!accountData,market:accountData?.market,sellerId:accountData?.sellerId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
// Validate that sellerId was extracted successfully
if (!accountData.sellerId || accountData.sellerId.trim() === "") {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:456',message:'handleAccountSubmit: sellerId validation failed',data:{accountData},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
+ // #endregion
throw new Error("Die eBay-URL konnte nicht verarbeitet werden. Bitte stelle sicher, dass es eine gültige eBay-Shop-URL ist.");
}
// Get current user
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:462',message:'handleAccountSubmit: before account.get',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
const authUser = await account.get();
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:465',message:'handleAccountSubmit: account.get success',data:{hasAuthUser:!!authUser,userId:authUser?.$id},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
// Check for duplicate account before creating
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:469',message:'handleAccountSubmit: before fetchManagedAccounts',data:{userId:authUser.$id},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
const existingAccounts = await fetchManagedAccounts(authUser.$id);
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:472',message:'handleAccountSubmit: fetchManagedAccounts success',data:{accountsCount:existingAccounts?.length || 0},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
const duplicateAccount = existingAccounts.find(
(acc) =>
acc.account_platform_account_id === accountData.sellerId &&
@@ -180,31 +659,52 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
);
if (duplicateAccount) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:480',message:'handleAccountSubmit: duplicate account found',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
throw new Error("Dieser Account ist bereits verbunden.");
}
// Create account in database
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:485',message:'handleAccountSubmit: before createManagedAccount',data:{userId:authUser.$id,accountData,itemsSold:accountData.stats?.itemsSold},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
await createManagedAccount(authUser.$id, {
account_platform_market: accountData.market,
account_platform_account_id: accountData.sellerId,
account_shop_name: accountData.shopName || null,
account_url: url,
account_status: accountData.status || "active",
+ account_sells: accountData.stats?.itemsSold ?? null, // Setze account_sells wenn verfügbar
});
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:494',message:'handleAccountSubmit: createManagedAccount success',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
+ // #endregion
// Account erstellt erfolgreich, rufe onStart auf
- onStart && onStart();
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:498',message:'handleAccountSubmit: before onStart',data:{hasOnStart:!!onStart},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ if (onStart) {
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:501',message:'handleAccountSubmit: calling onStart',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ await onStart();
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:504',message:'handleAccountSubmit: onStart completed, resetting phase',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
+ // #endregion
+ // Phase zurücksetzen, damit der Loading-Screen verschwindet
+ // (onStart versteckt das Gate, aber die Phase bleibt auf "loading")
+ setPhase("input");
+ setSubmitting(false);
+ }
// Trigger event to reload Dashboard accounts
- // #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:142',message:'handleAccountSubmit: account created, triggering reload event',data:{url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{});
- // #endregion
window.dispatchEvent(new CustomEvent('accountsUpdated'));
} catch (err) {
console.error("Fehler beim Erstellen des Accounts:", err);
-
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:106',message:'handleAccountSubmit: error caught',data:{url,errorMessage:err.message,errorCode:err.code,errorType:err.type,errorStack:err.stack?.substring(0,200)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:512',message:'handleAccountSubmit: error caught',data:{url,errorMessage:err.message,errorCode:err.code,errorType:err.type,errorStack:err.stack?.substring(0,200)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
// Show notification for URL validation, duplicate, or parsing errors
@@ -216,17 +716,20 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
err.message?.includes("already")
) {
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:205',message:'handleAccountSubmit: URL/duplicate error, showing notification',data:{errorMessage:err.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:523',message:'handleAccountSubmit: URL/duplicate error, showing notification',data:{errorMessage:err.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
// Use the actual error message or default message
setNotificationMessage(err.message || "bitte eine gueltige url verwenden!");
setShowNotification(true);
} else {
// #region agent log
- fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:175',message:'handleAccountSubmit: non-URL error, setting submitError',data:{errorMessage:err.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:530',message:'handleAccountSubmit: non-URL error, setting submitError',data:{errorMessage:err.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
setSubmitError(err.message || "Fehler beim Erstellen des Accounts. Bitte versuche es erneut.");
}
+ // #region agent log
+ fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'OnboardingGate.jsx:534',message:'handleAccountSubmit: error handler - switching back to input phase',data:{},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H4'})}).catch(()=>{});
+ // #endregion
setPhase("input");
setSubmitting(false);
}
@@ -235,7 +738,7 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
return (
@@ -277,11 +780,11 @@ export const OnboardingGate = ({ userName, onStart, loading, error }) => {
duration={4000}
/>
- {/* Shuffle and Input Phases - Combined AnimatePresence for smooth transition */}
+ {/* Welcome, Extension and Input Phases - Combined AnimatePresence for smooth transition */}
- {phase === "shuffle" && (
+ {phase === "welcome" && (
{
)}
+
+ {phase === "extension" && (
+
+
+
+ Lade die
+ C
+ h
+ r
+ o
+ m
+ e
+
+ E
+ x
+ t
+ e
+ n
+ s
+ i
+ o
+ n
+ herunter und aktiviere sie
+
+
+ {!extensionDownloaded ? (
+
+ ) : (
+
+ )}
+
+ {userExtensionLoaded ? (
+
+
+
Extension aktiviert! Weiterleitung...
+
+ ) : extensionDetected ? (
+
+
+
Extension erkannt! Weiterleitung...
+
+ ) : (
+ <>
+
+
+
Warte auf Extension...
+
+ >
+ )}
+
+
+ )}
{phase === "input" && (
{
const { open, animate } = useSidebar();
+ const disabled = !!link.disabled;
+ const handleClick = (e) => {
+ if (disabled) {
+ e.preventDefault();
+ return;
+ }
+ link.onClick?.(e);
+ };
return (
{link.icon}
+
+ {LETTERS.map((char, i) => (
+
+ {char}
+
+ ))}
+
{Math.round(percent)}%
+
+
+
+ );
+}
diff --git a/Server/src/components/ui/colourful-text.jsx b/Server/src/components/ui/colourful-text.jsx
index 16b0d88..0095e06 100644
--- a/Server/src/components/ui/colourful-text.jsx
+++ b/Server/src/components/ui/colourful-text.jsx
@@ -2,8 +2,8 @@
import React from "react";
import { motion } from "motion/react";
-export default function ColourfulText({ text }) {
- const colors = [
+export default function ColourfulText({ text, usePurpleTheme = false }) {
+ const defaultColors = [
"rgb(131, 179, 32)",
"rgb(47, 195, 106)",
"rgb(42, 169, 210)",
@@ -15,6 +15,21 @@ export default function ColourfulText({ text }) {
"rgb(232, 98, 63)",
"rgb(249, 129, 47)",
];
+
+ const purpleColors = [
+ "rgb(174, 182, 192)",
+ "rgb(217, 141, 233)",
+ "rgb(212, 170, 235)",
+ "rgb(230, 170, 239)",
+ "rgb(231, 170, 240)",
+ "rgb(231, 170, 240)",
+ "rgb(231, 170, 240)",
+ "rgb(231, 170, 240)",
+ "rgb(231, 170, 240)",
+ "rgb(231, 170, 240)",
+ ];
+
+ const colors = usePurpleTheme ? purpleColors : defaultColors;
const [currentColors, setCurrentColors] = React.useState(colors);
const [count, setCount] = React.useState(0);
diff --git a/Server/src/components/ui/dotted-glow-background.jsx b/Server/src/components/ui/dotted-glow-background.jsx
new file mode 100644
index 0000000..2abf634
--- /dev/null
+++ b/Server/src/components/ui/dotted-glow-background.jsx
@@ -0,0 +1,260 @@
+"use client";
+import React, { useEffect, useRef, useState } from "react";
+
+/**
+ * Canvas-based dotted background that randomly glows and dims.
+ * - Uses a stable grid of dots.
+ * - Each dot gets its own phase + speed producing organic shimmering.
+ * - Handles high-DPI and resizes via ResizeObserver.
+ */
+export const DottedGlowBackground = ({
+ className,
+ gap = 12,
+ radius = 2,
+ color = "rgba(0,0,0,0.7)",
+ darkColor,
+ glowColor = "rgba(0, 170, 255, 0.85)",
+ darkGlowColor,
+ colorLightVar,
+ colorDarkVar,
+ glowColorLightVar,
+ glowColorDarkVar,
+ opacity = 0.6,
+ backgroundOpacity = 0,
+ speedMin = 0.4,
+ speedMax = 1.3,
+ speedScale = 1
+}) => {
+ const canvasRef = useRef(null);
+ const containerRef = useRef(null);
+ const [resolvedColor, setResolvedColor] = useState(color);
+ const [resolvedGlowColor, setResolvedGlowColor] = useState(glowColor);
+
+ // Resolve CSS variable value from the container or root
+ const resolveCssVariable = (el, variableName) => {
+ if (!variableName) return null;
+ const normalized = variableName.startsWith("--")
+ ? variableName
+ : `--${variableName}`;
+ const fromEl = getComputedStyle(el)
+ .getPropertyValue(normalized)
+ .trim();
+ if (fromEl) return fromEl;
+ const root = document.documentElement;
+ const fromRoot = getComputedStyle(root).getPropertyValue(normalized).trim();
+ return fromRoot || null;
+ };
+
+ const detectDarkMode = () => {
+ const root = document.documentElement;
+ if (root.classList.contains("dark")) return true;
+ if (root.classList.contains("light")) return false;
+ return (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
+ };
+
+ // Keep resolved colors in sync with theme changes and prop updates
+ useEffect(() => {
+ const container = containerRef.current ?? document.documentElement;
+
+ const compute = () => {
+ const isDark = detectDarkMode();
+
+ let nextColor = color;
+ let nextGlow = glowColor;
+
+ if (isDark) {
+ const varDot = resolveCssVariable(container, colorDarkVar);
+ const varGlow = resolveCssVariable(container, glowColorDarkVar);
+ nextColor = varDot || darkColor || nextColor;
+ nextGlow = varGlow || darkGlowColor || nextGlow;
+ } else {
+ const varDot = resolveCssVariable(container, colorLightVar);
+ const varGlow = resolveCssVariable(container, glowColorLightVar);
+ nextColor = varDot || nextColor;
+ nextGlow = varGlow || nextGlow;
+ }
+
+ setResolvedColor(nextColor);
+ setResolvedGlowColor(nextGlow);
+ };
+
+ compute();
+
+ const mql = window.matchMedia
+ ? window.matchMedia("(prefers-color-scheme: dark)")
+ : null;
+ const handleMql = () => compute();
+ mql?.addEventListener?.("change", handleMql);
+
+ const mo = new MutationObserver(() => compute());
+ mo.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ["class", "style"],
+ });
+
+ return () => {
+ mql?.removeEventListener?.("change", handleMql);
+ mo.disconnect();
+ };
+ }, [
+ color,
+ darkColor,
+ glowColor,
+ darkGlowColor,
+ colorLightVar,
+ colorDarkVar,
+ glowColorLightVar,
+ glowColorDarkVar,
+ ]);
+
+ useEffect(() => {
+ const el = canvasRef.current;
+ const container = containerRef.current;
+ if (!el || !container) return;
+
+ const ctx = el.getContext("2d");
+ if (!ctx) return;
+
+ let raf = 0;
+ let stopped = false;
+
+ const dpr = Math.max(1, window.devicePixelRatio || 1);
+
+ const resize = () => {
+ const { width, height } = container.getBoundingClientRect();
+ el.width = Math.max(1, Math.floor(width * dpr));
+ el.height = Math.max(1, Math.floor(height * dpr));
+ el.style.width = `${Math.floor(width)}px`;
+ el.style.height = `${Math.floor(height)}px`;
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ };
+
+ const ro = new ResizeObserver(resize);
+ ro.observe(container);
+ resize();
+
+ // Precompute dot metadata for a medium-sized grid and regenerate on resize
+ let dots = [];
+
+ const regenDots = () => {
+ dots = [];
+ const { width, height } = container.getBoundingClientRect();
+ const cols = Math.ceil(width / gap) + 2;
+ const rows = Math.ceil(height / gap) + 2;
+ const min = Math.min(speedMin, speedMax);
+ const max = Math.max(speedMin, speedMax);
+ for (let i = -1; i < cols; i++) {
+ for (let j = -1; j < rows; j++) {
+ const x = i * gap + (j % 2 === 0 ? 0 : gap * 0.5); // offset every other row
+ const y = j * gap;
+ // Randomize phase and speed slightly per dot
+ const phase = Math.random() * Math.PI * 2;
+ const span = Math.max(max - min, 0);
+ const speed = min + Math.random() * span; // configurable rad/s
+ dots.push({ x, y, phase, speed });
+ }
+ }
+ };
+
+ const regenThrottled = () => {
+ regenDots();
+ };
+
+ regenDots();
+
+ let last = performance.now();
+
+ const draw = (now) => {
+ if (stopped) return;
+ const dt = (now - last) / 1000; // seconds
+ last = now;
+ const { width, height } = container.getBoundingClientRect();
+
+ ctx.clearRect(0, 0, el.width, el.height);
+ ctx.globalAlpha = opacity;
+
+ // optional subtle background fade for depth (defaults to 0 = transparent)
+ if (backgroundOpacity > 0) {
+ const grad = ctx.createRadialGradient(
+ width * 0.5,
+ height * 0.4,
+ Math.min(width, height) * 0.1,
+ width * 0.5,
+ height * 0.5,
+ Math.max(width, height) * 0.7
+ );
+ grad.addColorStop(0, "rgba(0,0,0,0)");
+ grad.addColorStop(1, `rgba(0,0,0,${Math.min(Math.max(backgroundOpacity, 0), 1)})`);
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, width, height);
+ }
+
+ // animate dots
+ ctx.save();
+ ctx.fillStyle = resolvedColor;
+
+ const time = (now / 1000) * Math.max(speedScale, 0);
+ for (let i = 0; i < dots.length; i++) {
+ const d = dots[i];
+ // Linear triangle wave 0..1..0 for linear glow/dim
+ const mod = (time * d.speed + d.phase) % 2;
+ const lin = mod < 1 ? mod : 2 - mod; // 0..1..0
+ const a = 0.25 + 0.55 * lin; // 0.25..0.8 linearly
+
+ // draw glow when bright
+ if (a > 0.6) {
+ const glow = (a - 0.6) / 0.4; // 0..1
+ ctx.shadowColor = resolvedGlowColor;
+ ctx.shadowBlur = 6 * glow;
+ } else {
+ ctx.shadowColor = "transparent";
+ ctx.shadowBlur = 0;
+ }
+
+ ctx.globalAlpha = a * opacity;
+ ctx.beginPath();
+ ctx.arc(d.x, d.y, radius, 0, Math.PI * 2);
+ ctx.fill();
+ }
+ ctx.restore();
+
+ raf = requestAnimationFrame(draw);
+ };
+
+ const handleResize = () => {
+ resize();
+ regenThrottled();
+ };
+
+ window.addEventListener("resize", handleResize);
+ raf = requestAnimationFrame(draw);
+
+ return () => {
+ stopped = true;
+ cancelAnimationFrame(raf);
+ window.removeEventListener("resize", handleResize);
+ ro.disconnect();
+ };
+ }, [
+ gap,
+ radius,
+ resolvedColor,
+ resolvedGlowColor,
+ opacity,
+ backgroundOpacity,
+ speedMin,
+ speedMax,
+ speedScale,
+ ]);
+
+ return (
+
+
+
+ );
+};
diff --git a/Server/src/context/ScanContext.jsx b/Server/src/context/ScanContext.jsx
new file mode 100644
index 0000000..59ea152
--- /dev/null
+++ b/Server/src/context/ScanContext.jsx
@@ -0,0 +1,51 @@
+import React, { createContext, useContext, useState, useCallback } from "react";
+
+const ScanContext = createContext(null);
+
+export function useScan() {
+ const ctx = useContext(ScanContext);
+ if (!ctx) {
+ throw new Error("useScan must be used within ScanProvider");
+ }
+ return ctx;
+}
+
+/**
+ * ScanProvider – hält scanning + scanProgress für Scan-UI (Loader, Dashboard ausblenden, etc.)
+ */
+export function ScanProvider({ children }) {
+ const [scanning, setScanning] = useState(false);
+ const [scanProgress, setScanProgress] = useState({
+ percent: 0,
+ phase: "idle",
+ total: 0,
+ current: 0,
+ complete: false,
+ });
+
+ const startScan = useCallback(() => {
+ setScanning(true);
+ setScanProgress({ percent: 0, phase: "listing", total: 0, current: 0, complete: false });
+ }, []);
+
+ const updateProgress = useCallback((data) => {
+ setScanProgress((prev) => ({ ...prev, ...data }));
+ }, []);
+
+ const endScan = useCallback(() => {
+ setScanning(false);
+ setScanProgress({ percent: 0, phase: "idle", total: 0, current: 0, complete: false });
+ }, []);
+
+ const value = {
+ scanning,
+ setScanning,
+ scanProgress,
+ setScanProgress,
+ startScan,
+ updateProgress,
+ endScan,
+ };
+
+ return {children};
+}
diff --git a/Server/src/index.css b/Server/src/index.css
index 2d493a1..97a6703 100644
--- a/Server/src/index.css
+++ b/Server/src/index.css
@@ -41,3 +41,9 @@
}
}
}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/Server/src/main.jsx b/Server/src/main.jsx
index 89f91e5..0b61d8c 100644
--- a/Server/src/main.jsx
+++ b/Server/src/main.jsx
@@ -1,10 +1,13 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
+import { ScanProvider } from './context/ScanContext'
import './index.css'
createRoot(document.getElementById('root')).render(
-
+
+
+
,
)
diff --git a/Server/src/pages/AccountsPage.jsx b/Server/src/pages/AccountsPage.jsx
index 6845a9c..6ac08d1 100644
--- a/Server/src/pages/AccountsPage.jsx
+++ b/Server/src/pages/AccountsPage.jsx
@@ -99,7 +99,7 @@ export const AccountsPage = () => {
updatePayload.account_platform_account_id = parsedData.sellerId;
}
- // Shop-Name und account_sells können auch leer sein (optional)
+ // Shop-Name kann auch leer sein (optional)
updatePayload.account_shop_name = parsedData.shopName || null;
updatePayload.account_sells = parsedData.stats?.itemsSold ?? null;
@@ -584,21 +584,6 @@ export const AccountsPage = () => {
-
-
-
-
- Automatisch aus dem eBay-Profil gelesen.
-
-
-