Merge remote changes and update project files

This commit is contained in:
2026-01-26 06:48:58 +01:00
24 changed files with 2943 additions and 850 deletions

View File

@@ -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"}

View File

@@ -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<tabId, { timeout, originalSender, resolve }>
const activeScanRequests = new Map(); // Map<tabId, { timeout, sendResponse }>
const activeScanRequests = new Map(); // Map<tabId, { timeout, sendResponse }>;
/** 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);

View File

@@ -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") {

View File

@@ -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;
}
/**

View File

@@ -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}`);
});

View File

@@ -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",

BIN
Server/public/extension.zip Normal file

Binary file not shown.

View File

@@ -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: (
<IconShoppingBag className="h-5 w-5 shrink-0 text-neutral-700 dark:text-neutral-200" />
),
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"}
/>
)}
<div style={{ display: showGate ? "none" : "block" }}>
@@ -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"
)}>
<Sidebar open={sidebarOpen} setOpen={setSidebarOpen} animate={true}>
<SidebarBody className="justify-between gap-10">
<div className="flex flex-1 flex-col overflow-x-hidden overflow-y-auto">
<SidebarHeader />
<div className="mt-8 flex flex-col gap-2">
{links.map((link, idx) => (
<SidebarLink key={idx} link={link} />
))}
{!scanning && (
<Sidebar open={sidebarOpen} setOpen={setSidebarOpen} animate={true}>
<SidebarBody className="justify-between gap-10">
<div className="flex flex-1 flex-col overflow-x-hidden overflow-y-auto">
<SidebarHeader />
<div className="mt-8 flex flex-col gap-2">
{links.map((link, idx) => (
<SidebarLink key={idx} link={link} />
))}
</div>
</div>
</div>
<div>
<LogoutButton onClick={(e) => {
e.preventDefault();
logout();
}} />
</div>
</SidebarBody>
</Sidebar>
<div>
<LogoutButton onClick={(e) => {
e.preventDefault();
logout();
}} />
</div>
</SidebarBody>
</Sidebar>
)}
{renderContent()}
</div>
{scanning && (
<ScanningLoader percent={scanProgress?.percent ?? 0} />
)}
</div>
</>
)}

View File

@@ -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();
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -131,11 +131,24 @@ export const SidebarLink = ({
...props
}) => {
const { open, animate } = useSidebar();
const disabled = !!link.disabled;
const handleClick = (e) => {
if (disabled) {
e.preventDefault();
return;
}
link.onClick?.(e);
};
return (
<a
href={link.href}
onClick={link.onClick}
className={cn("flex items-center justify-start gap-2 group/sidebar py-2", className)}
onClick={handleClick}
className={cn(
"flex items-center justify-start gap-2 group/sidebar py-2",
disabled && "pointer-events-none opacity-50 cursor-not-allowed",
className
)}
aria-disabled={disabled}
{...props}>
{link.icon}
<motion.span

View File

@@ -0,0 +1,113 @@
import React from "react";
import styled from "styled-components";
const StyledWrapper = styled.div`
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9999;
pointer-events: none;
.loader-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 180px;
height: 180px;
font-family: "Inter", sans-serif;
font-size: 1.2em;
font-weight: 300;
color: white;
border-radius: 50%;
background-color: transparent;
user-select: none;
}
.loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 50%;
background-color: transparent;
animation: loader-rotate 2s linear infinite;
z-index: 0;
}
@keyframes loader-rotate {
0% {
transform: rotate(90deg);
box-shadow:
0 10px 20px 0 #fff inset,
0 20px 30px 0 #ad5fff inset,
0 60px 60px 0 #471eec inset;
}
50% {
transform: rotate(270deg);
box-shadow:
0 10px 20px 0 #fff inset,
0 20px 10px 0 #d60a47 inset,
0 40px 60px 0 #311e80 inset;
}
100% {
transform: rotate(450deg);
box-shadow:
0 10px 20px 0 #fff inset,
0 20px 30px 0 #ad5fff inset,
0 60px 60px 0 #471eec inset;
}
}
.loader-letter {
display: inline-block;
opacity: 0.4;
transform: translateY(0);
animation: loader-letter-anim 2s infinite;
z-index: 1;
border-radius: 50ch;
border: none;
}
.loader-letter:nth-child(1) { animation-delay: 0s; }
.loader-letter:nth-child(2) { animation-delay: 0.1s; }
.loader-letter:nth-child(3) { animation-delay: 0.2s; }
.loader-letter:nth-child(4) { animation-delay: 0.3s; }
.loader-letter:nth-child(5) { animation-delay: 0.4s; }
.loader-letter:nth-child(6) { animation-delay: 0.5s; }
.loader-letter:nth-child(7) { animation-delay: 0.6s; }
.loader-letter:nth-child(8) { animation-delay: 0.7s; }
.loader-letter:nth-child(9) { animation-delay: 0.8s; }
.loader-letter:nth-child(10) { animation-delay: 0.9s; }
@keyframes loader-letter-anim {
0%, 100% { opacity: 0.4; transform: translateY(0); }
20% { opacity: 1; transform: scale(1.15); }
40% { opacity: 0.7; transform: translateY(0); }
}
.loader-percent {
margin-left: 2px;
opacity: 0.9;
z-index: 1;
}
`;
const LETTERS = "Scanning".split("");
export default function ScanningLoader({ percent = 0 }) {
return (
<StyledWrapper>
<div className="loader-wrapper">
{LETTERS.map((char, i) => (
<span key={i} className="loader-letter">
{char}
</span>
))}
<span className="loader-percent">{Math.round(percent)}%</span>
<div className="loader" />
</div>
</StyledWrapper>
);
}

View File

@@ -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);

View File

@@ -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 (
<div
ref={containerRef}
className={className}
style={{ position: "absolute", inset: 0 }}>
<canvas
ref={canvasRef}
style={{ display: "block", width: "100%", height: "100%" }} />
</div>
);
};

View File

@@ -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 <ScanContext.Provider value={value}>{children}</ScanContext.Provider>;
}

View File

@@ -41,3 +41,9 @@
}
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}

View File

@@ -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(
<StrictMode>
<App />
<ScanProvider>
<App />
</ScanProvider>
</StrictMode>,
)

View File

@@ -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 = () => {
</p>
</div>
<div>
<label className="mb-1.5 block text-xs font-medium text-[var(--muted)]">
Artikel verkauft (Auto)
</label>
<input
type="text"
value={parsedData.stats?.itemsSold ?? "-"}
readOnly
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2 text-sm text-[var(--text)] opacity-75 dark:bg-neutral-900 dark:border-neutral-700"
/>
<p className="mt-1 text-xs text-[var(--muted)]">
Automatisch aus dem eBay-Profil gelesen.
</p>
</div>
<div>
<label className="mb-1.5 block text-xs font-medium text-[var(--muted)]">
Sales (Auto)

View File

@@ -200,12 +200,8 @@ export async function createManagedAccount(authUserId, accountData) {
account_platform_account_id,
account_shop_name: accountData.account_shop_name || null,
account_url: accountData.account_url || null,
account_sells: accountData.account_sells ?? null,
account_managed: true, // Immer true für über die UI erstellte Accounts
account_sells: accountData.account_sells ?? 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:'accountsService.js:72',message:'createManagedAccount: payload before Appwrite',data:{account_sells:payload.account_sells,accountData_account_sells:accountData.account_sells},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{});
// #endregion
// account_status ist optional - aufgrund Schema-Konflikt vorerst weglassen
// TODO: Schema in Appwrite prüfen und korrigieren (Enum-Feld sollte String akzeptieren, nicht Array)
@@ -261,10 +257,6 @@ export async function updateManagedAccount(accountId, accountData) {
}
});
// #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:'accountsService.js:133',message:'updateManagedAccount: before updateDocument',data:{accountId,payload,payloadKeys:Object.keys(payload)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
// #endregion
const document = await databases.updateDocument(
databaseId,
accountsCollectionId,
@@ -272,15 +264,9 @@ export async function updateManagedAccount(accountId, accountData) {
payload
);
// #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:'accountsService.js:147',message:'updateManagedAccount: success',data:{accountId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{});
// #endregion
return document;
} catch (e) {
console.error("Fehler beim Aktualisieren des Accounts:", 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:'accountsService.js:149',message:'updateManagedAccount: error',data:{accountId,errorCode:e.code,errorMessage:e.message,errorType:e.type},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{});
// #endregion
throw e;
}
}

View File

@@ -129,9 +129,6 @@ async function getExtensionId() {
try {
// Methode 1: Verwende gecachte Extension-ID (via postMessage vom Content Script empfangen)
if (cachedExtensionId) {
// #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:'ebayParserService.js:135',message:'getExtensionId: found via cache',data:{cachedExtensionId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
return cachedExtensionId;
}
@@ -147,9 +144,6 @@ async function getExtensionId() {
}
}
// #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:'ebayParserService.js:150',message:'getExtensionId: not found after retries',data:{hasWindow:typeof window!=='undefined'},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
return null; // Nicht verfügbar
} catch (e) {
return null;
@@ -163,10 +157,6 @@ async function getExtensionId() {
* @throws {Error} - "Extension not available" oder andere Fehler
*/
async function parseViaExtension(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:'ebayParserService.js:165',message:'parseViaExtension: entry',data:{url,hasChrome:typeof chrome!=='undefined',hasRuntime:typeof chrome!=='undefined'&&!!chrome.runtime},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
// Validierung
if (!url || typeof url !== 'string') {
throw new Error("Invalid URL");
@@ -178,10 +168,6 @@ async function parseViaExtension(url) {
try {
const extensionId = await getExtensionId();
// #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:'ebayParserService.js:175',message:'parseViaExtension: got extension ID',data:{extensionId,url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
// Versuche chrome.runtime.sendMessage (mit oder ohne Extension-ID)
return new Promise((resolve, reject) => {
const message = {
@@ -189,48 +175,43 @@ async function parseViaExtension(url) {
url: 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:'ebayParserService.js:178',message:'parseViaExtension: sending message',data:{extensionId,url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
// SendMessage-Callback
const sendMessageCallback = (response) => {
// Check for Chrome runtime errors
if (chrome.runtime.lastError) {
const errorMsg = chrome.runtime.lastError.message || "Extension communication 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:'ebayParserService.js:158',message:'parseViaExtension: chrome.runtime.sendMessage error',data:{error:errorMsg,extensionId},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
reject(new Error(errorMsg));
return;
}
if (response && response.ok && response.data) {
// Ensure stats object is included (even if empty)
let sellerId = response.data.sellerId || "";
// Fallback: Wenn Extension keinen sellerId liefert, versuche aus URL zu extrahieren
if (!sellerId || sellerId.trim() === "") {
// Versuche _ssn Parameter aus Suchergebnis-URLs zu extrahieren
const ssnMatch = url.match(/[?&]_ssn=([^&]+)/i);
if (ssnMatch && ssnMatch[1]) {
sellerId = decodeURIComponent(ssnMatch[1]).trim();
}
}
const data = {
sellerId: response.data.sellerId || "",
sellerId: sellerId,
shopName: response.data.shopName || "",
market: response.data.market || "US",
status: response.data.status || "unknown",
stats: response.data.stats || {}
};
// #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:'ebayParserService.js:196',message:'parseViaExtension: response success',data:{hasStats:!!response.data.stats,itemsSold:response.data.stats?.itemsSold,stats:response.data.stats},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
resolve(data);
} 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:'ebayParserService.js:210',message:'parseViaExtension: response failed',data:{error:response?.error,hasResponse:!!response,ok:response?.ok},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
reject(new Error(response?.error || "Extension parsing failed"));
}
};
// Benötigt Extension-ID (sendMessage von Webseiten aus erfordert immer Extension-ID)
if (!extensionId) {
// #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:'ebayParserService.js:175',message:'parseViaExtension: no extension ID',data:{hasWindowExtensionId:!!(typeof window!=='undefined'&&window.__EBAY_EXTENSION_ID__)},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
reject(new Error("Extension ID not available"));
return;
}
@@ -265,8 +246,19 @@ async function parseViaExtension(url) {
window.removeEventListener('message', responseHandler);
if (event.data?.ok && event.data?.data) {
let sellerId = event.data.data.sellerId || "";
// Fallback: Wenn Extension keinen sellerId liefert, versuche aus URL zu extrahieren
if (!sellerId || sellerId.trim() === "") {
// Versuche _ssn Parameter aus Suchergebnis-URLs zu extrahieren
const ssnMatch = url.match(/[?&]_ssn=([^&]+)/i);
if (ssnMatch && ssnMatch[1]) {
sellerId = decodeURIComponent(ssnMatch[1]).trim();
}
}
const data = {
sellerId: event.data.data.sellerId || "",
sellerId: sellerId,
shopName: event.data.data.shopName || "",
market: event.data.data.market || "US",
status: event.data.data.status || "unknown",
@@ -330,8 +322,11 @@ export async function parseViaExtensionScanProducts(url, accountId) {
accountId: accountId
};
const SCAN_TIMEOUT_MS = 300000;
// SendMessage-Callback
const sendMessageCallback = (response) => {
clearTimeout(timeoutId);
// Check for Chrome runtime errors
if (chrome.runtime.lastError) {
const errorMsg = chrome.runtime.lastError.message || "Extension communication error";
@@ -339,11 +334,12 @@ export async function parseViaExtensionScanProducts(url, accountId) {
return;
}
if (response && response.ok && response.data) {
const items = response.data.items || [];
const meta = response.data.meta || response.meta || {};
console.log("[ebayParserService] SCAN_PRODUCTS response:", response);
if (response && response.ok) {
const items = response.data?.items || response.items || [];
const meta = response.data?.meta || response.meta || {};
// Wenn items leer oder ok:false, werfe Fehler mit meta
if (!Array.isArray(items) || items.length === 0) {
const errorMsg = response?.error || "no_items_found";
const error = new Error(`SCAN_PRODUCTS failed: ${errorMsg} (${meta.pageType || "unknown"})`);
@@ -352,30 +348,27 @@ export async function parseViaExtensionScanProducts(url, accountId) {
return;
}
// Erfolg: gib items zurück
resolve(items);
} else {
// Fehler: sende error + meta
const meta = response?.meta || {};
const errorMsg = response?.error || "Extension scanning failed";
console.log("[ebayParserService] SCAN_PRODUCTS error:", errorMsg, "meta:", meta);
const error = new Error(`SCAN_PRODUCTS failed: ${errorMsg} (${meta.pageType || "unknown"})`);
error.meta = meta;
reject(error);
}
};
// Benötigt Extension-ID (sendMessage von Webseiten aus erfordert immer Extension-ID)
if (!extensionId) {
reject(new Error("Extension ID not available"));
return;
}
chrome.runtime.sendMessage(extensionId, message, sendMessageCallback);
// Timeout nach 20s (Extension hat intern 20s)
setTimeout(() => {
const timeoutId = setTimeout(() => {
reject(new Error("Extension timeout"));
}, 20000);
}, SCAN_TIMEOUT_MS);
chrome.runtime.sendMessage(extensionId, message, sendMessageCallback);
});
} catch (error) {
// Chrome API Fehler: weiter zu Methode 2
@@ -388,45 +381,51 @@ export async function parseViaExtensionScanProducts(url, accountId) {
// Methode 2: Window flag + postMessage (falls Content Script Relay vorhanden)
if (typeof window !== 'undefined' && window.__EBAY_EXTENSION__ === true) {
const SCAN_TIMEOUT_MS = 300000;
return new Promise((resolve, reject) => {
const messageId = `scan_${Date.now()}_${Math.random()}`;
// Listener für Antwort
let settled = false;
const finish = (fn) => {
if (settled) return;
settled = true;
clearTimeout(timeoutId);
window.removeEventListener('message', responseHandler);
fn();
};
const responseHandler = (event) => {
if (event.data?.source !== 'eship-extension' || event.data?.messageId !== messageId) {
return;
}
window.removeEventListener('message', responseHandler);
if (event.data?.ok && event.data?.data) {
const items = event.data.data.items || event.data.items || [];
const meta = event.data.data.meta || event.data.meta || {};
// Wenn items leer oder ok:false, werfe Fehler mit meta
if (!Array.isArray(items) || items.length === 0) {
const errorMsg = event.data?.error || "no_items_found";
const error = new Error(`SCAN_PRODUCTS failed: ${errorMsg} (${meta.pageType || "unknown"})`);
error.meta = meta;
reject(error);
finish(() => reject(error));
return;
}
// Erfolg: gib items zurück
resolve(items);
finish(() => resolve(items));
} else {
// Fehler: sende error + meta
const meta = event.data?.meta || event.data?.data?.meta || {};
const errorMsg = event.data?.error || "Extension scanning failed";
const error = new Error(`SCAN_PRODUCTS failed: ${errorMsg} (${meta.pageType || "unknown"})`);
error.meta = meta;
reject(error);
finish(() => reject(error));
}
};
window.addEventListener('message', responseHandler);
// Sende Request via postMessage
const timeoutId = setTimeout(() => {
finish(() => reject(new Error("Extension timeout")));
}, SCAN_TIMEOUT_MS);
window.postMessage({
source: 'eship-webapp',
action: 'SCAN_PRODUCTS',
@@ -434,12 +433,6 @@ export async function parseViaExtensionScanProducts(url, accountId) {
accountId: accountId,
messageId: messageId
}, '*');
// Timeout
setTimeout(() => {
window.removeEventListener('message', responseHandler);
reject(new Error("Extension timeout"));
}, 20000);
});
}
@@ -447,6 +440,31 @@ export async function parseViaExtensionScanProducts(url, accountId) {
throw new Error("Extension not available");
}
/**
* Holt den aktuellen Scan-Fortschritt von der Extension (für Polling während SCAN_PRODUCTS).
* @returns {Promise<{ percent: number, phase: string, total: number, current: number, complete: boolean }|null>}
*/
export async function getScanProgress() {
if (typeof chrome === "undefined" || !chrome?.runtime?.sendMessage) {
return null;
}
try {
const extensionId = await getExtensionId();
if (!extensionId) return null;
return new Promise((resolve) => {
chrome.runtime.sendMessage(extensionId, { action: "GET_SCAN_PROGRESS" }, (response) => {
if (chrome.runtime.lastError) {
resolve(null);
return;
}
resolve(response ?? null);
});
});
} catch {
return null;
}
}
/**
* Parst eine eBay-URL mit Stub-Logik (deterministisch, keine Network-Calls)
* @param {string} url - eBay-Verkäuferprofil oder Shop-URL
@@ -472,9 +490,18 @@ async function parseViaStub(url) {
const hash = stableHash(url);
const market = extractMarketFromUrl(url);
// Seller ID: Deterministic aus URL-Hash
// Format: "ebay_" + hash (first 10 chars)
const sellerId = `ebay_${hash.slice(0, 10)}`;
// Seller ID: Versuche zuerst aus URL zu extrahieren (_ssn Parameter)
let sellerId = "";
const ssnMatch = url.match(/[?&]_ssn=([^&]+)/i);
if (ssnMatch && ssnMatch[1]) {
sellerId = decodeURIComponent(ssnMatch[1]).trim();
}
// Fallback: Deterministic aus URL-Hash wenn kein _ssn Parameter gefunden
if (!sellerId || sellerId.trim() === "") {
// Format: "ebay_" + hash (first 10 chars)
sellerId = `ebay_${hash.slice(0, 10)}`;
}
// Shop Name: Generiert aus Hash (last 4 chars als Suffix)
const shopNameSuffix = hash.slice(-4);
@@ -504,27 +531,14 @@ async function parseViaStub(url) {
export async function parseEbayAccount(url) {
// Versuche IMMER Extension-Pfad zuerst (auch wenn Flag nicht gesetzt)
// parseViaExtension prüft selbst, ob Extension verfügbar ist
// #region agent log
const extAvailable = isExtensionAvailable();
const hasChromeRuntime = typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.sendMessage;
fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'ebayParserService.js:292',message:'parseEbayAccount: route decision',data:{extAvailable,hasChromeRuntime,url},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
try {
// Versuche Extension zu nutzen (auch wenn Flag nicht gesetzt - parseViaExtension prüft selbst)
return await parseViaExtension(url);
} catch (e) {
// Extension-Fehler: Fallback zu Stub
console.warn("Extension parsing failed, falling back to stub:", e.message);
// #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:'ebayParserService.js:299',message:'parseEbayAccount: extension error, using stub',data:{error:e.message},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
}
// Fallback: Stub-Implementierung
const stubResult = await parseViaStub(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:'ebayParserService.js:304',message:'parseEbayAccount: stub result',data:{itemsSold:stubResult.stats?.itemsSold},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{});
// #endregion
return stubResult;
return await parseViaStub(url);
}

View File

@@ -11,6 +11,46 @@ import { parseViaExtensionScanProducts } from "./ebayParserService";
const productsCollectionId = import.meta.env.VITE_APPWRITE_PRODUCTS_COLLECTION_ID || "products";
/** Deutsche eBay-Zustandsbezeichnungen → product_condition Enum (längere zuerst) */
const CONDITION_DE_TO_ENUM = [
["neu mit etikett", "new_with_tags"],
["neu ohne etikett", "new_without_tags"],
["neu mit mängeln", "new_with_defects"],
["vom hersteller generalüberholt", "manufacturer_refurbished"],
["vom hersteller generalueberholt", "manufacturer_refurbished"],
["vom verkäufer generalüberholt", "seller_refurbished"],
["vom verkäufer generalueberholt", "seller_refurbished"],
["vom verkaeufer generalüberholt", "seller_refurbished"],
["vom verkaeufer generalueberholt", "seller_refurbished"],
["defekt oder unvollständig", "for_parts_or_not_working"],
["defekt oder unvollstaendig", "for_parts_or_not_working"],
["sehr gut", "very_good"],
["wie neu", "like_new"],
["ausstellerstück", "display_item"],
["ausstellerstueck", "display_item"],
["unbenutzt", "unused"],
["antik", "antique"],
["neu", "new"],
["gebraucht", "used"],
["gut", "good"],
["akzeptabel", "acceptable"],
];
/**
* Mappt deutsche eBay-Zustandsangabe auf product_condition Enum.
* @param {string|null|undefined} de - z.B. "Neu", "Gebraucht", "Neu mit Etikett"
* @returns {string|null} Enum-Wert oder null wenn nicht zuordenbar
*/
function mapConditionDeToEnum(de) {
if (de == null || typeof de !== "string") return null;
const n = de.trim().toLowerCase().replace(/\s+/g, " ");
if (!n) return null;
for (const [phrase, enumVal] of CONDITION_DE_TO_ENUM) {
if (n.includes(phrase)) return enumVal;
}
return null;
}
/**
* Lädt alle Products für einen bestimmten Account
* @param {string} accountId - ID des Accounts (product_account_id)
@@ -68,6 +108,31 @@ export async function listProductsByAccount(accountId, options = {}) {
}
}
const EXISTING_PRODUCTS_PAGE_SIZE = 100;
/**
* Lädt alle Products eines Accounts für Duplikat-Prüfung (paginiert, Appwrite-Limit 100/Request).
* @param {string} accountId
* @returns {Promise<Array>}
*/
async function fetchAllProductsByAccount(accountId) {
const all = [];
let offset = 0;
let hasMore = true;
while (hasMore) {
const page = await listProductsByAccount(accountId, {
limit: EXISTING_PRODUCTS_PAGE_SIZE,
offset,
orderBy: "$createdAt",
orderType: "asc",
});
all.push(...page);
hasMore = page.length === EXISTING_PRODUCTS_PAGE_SIZE;
offset += page.length;
}
return all;
}
/**
* Lädt ein einzelnes Product nach ID
* @param {string} productId - ID des Products
@@ -118,33 +183,97 @@ export async function scanProductsForAccount(accountId) {
}
// 2. Extension aufrufen: scanne Produkte
const items = await parseViaExtensionScanProducts(account.account_url, accountId);
let items;
try {
items = await parseViaExtensionScanProducts(account.account_url, accountId);
} catch (extensionError) {
// Extension-Fehler: Parsing failed
console.error("Extension-Fehler beim Scannen:", extensionError);
// Erstelle detaillierte Fehlermeldung mit meta-Informationen
const meta = extensionError.meta || {};
let errorMessage = extensionError.message || "Parsing failed";
// Füge meta-Details hinzu, falls vorhanden
if (meta.pageType) {
errorMessage += ` (Seitentyp: ${meta.pageType})`;
}
if (meta.reason) {
errorMessage += ` (Grund: ${meta.reason})`;
}
if (meta.finalUrl) {
errorMessage += ` (URL: ${meta.finalUrl})`;
}
const detailedError = new Error(`Extension-Fehler: ${errorMessage}`);
detailedError.meta = meta;
throw detailedError;
}
// #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:'productsService.js:scanProductsForAccount',message:'items from extension',data:{itemsCount:items?.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H4'})}).catch(()=>{});
// #endregion
// 3. Response-Items zu Product-Schema mappen
const mappedProducts = items.map(item => {
// Validiere, dass platformProductId vorhanden ist
if (!item.platformProductId) {
console.warn("Item ohne platformProductId übersprungen:", item);
return null;
}
const id = String(item.platformProductId).trim();
if (id === "123456" || id.length < 10) {
console.warn("Item mit Platzhalter-/ungültiger ID übersprungen (eBay-IDs 1012 Ziffern):", id);
return null;
}
return {
product_platform_product_id: item.platformProductId,
product_title: item.title || "",
product_price: item.price ?? undefined, // undefined statt null für Appwrite
product_currency: item.currency ?? undefined, // auto-fill from market if undefined
product_price: item.price ?? undefined,
product_currency: item.currency ?? undefined,
product_url: item.url || "",
product_status: item.status ?? "unknown",
product_category: item.category ?? "unknown",
product_condition: item.condition ?? "unknown"
product_category: String(item.category ?? "unknown").slice(0, 255),
product_condition: mapConditionDeToEnum(item.condition) ?? "used",
product_quantity_sold: item.quantitySold ?? undefined,
product_quantity_available: item.quantityAvailable ?? undefined,
product_watch_count: item.watchCount ?? undefined,
product_in_carts_count: item.inCartsCount ?? undefined
};
}).filter(Boolean); // Entferne null-Einträge
// #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:'productsService.js:scanProductsForAccount',message:'mapped products',data:{mappedCount:mappedProducts.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
// #endregion
// 4. upsertProductsForAccount aufrufen
const result = await upsertProductsForAccount(accountId, mappedProducts);
let result;
try {
result = await upsertProductsForAccount(accountId, mappedProducts);
} catch (dbError) {
// Datenbank-Fehler: Collection oder Attribute fehlen
console.error("Datenbank-Fehler beim Speichern:", dbError);
// Prüfe auf spezifische Datenbank-Fehler
if (dbError.code === 404 || dbError.type === 'collection_not_found') {
throw new Error("Datenbank-Fehler: Products-Collection existiert nicht. Bitte Datenbank-Schema einrichten.");
}
if (dbError.code === 400 || dbError.message?.includes('attribute')) {
throw new Error(`Datenbank-Fehler: Ein Attribut fehlt oder ist ungültig. Details: ${dbError.message}`);
}
if (dbError.code === 401 || dbError.type === 'permission_denied') {
throw new Error("Datenbank-Fehler: Keine Berechtigung zum Speichern von Produkten. Bitte Berechtigungen prüfen.");
}
// Generischer Datenbank-Fehler
throw new Error(`Datenbank-Fehler beim Speichern: ${dbError.message || "Unbekannter Fehler"}`);
}
// 5. account_last_scan_at aktualisieren
await updateAccountLastScanAt(accountId, new Date().toISOString());
try {
await updateAccountLastScanAt(accountId, new Date().toISOString());
} catch (updateError) {
// Nicht kritisch, nur loggen
console.warn("Fehler beim Aktualisieren von account_last_scan_at:", updateError);
}
// 6. Return { created, updated }
return result;
@@ -186,11 +315,11 @@ export async function upsertProductsForAccount(accountId, products) {
const currency = deriveCurrencyFromMarket(market);
const platform = "ebay"; // Enum-Werte sind lowercase gemäß Fehlermeldung: [amazon], [ebay]
// Lade bestehende Produkte für Duplikat-Prüfung
const existingProducts = await listProductsByAccount(accountId, {
limit: 1000,
offset: 0,
});
// Lade alle bestehenden Produkte (paginiert, Appwrite max 100/Request)
const existingProducts = await fetchAllProductsByAccount(accountId);
// #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:'productsService.js:upsertProductsForAccount',message:'existing products loaded',data:{productsToUpsert:products.length,existingCount:existingProducts.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
// #endregion
// Erstelle Map von platform_product_id -> bestehendes Produkt
const existingProductsMap = new Map();
@@ -234,22 +363,43 @@ export async function upsertProductsForAccount(accountId, products) {
);
updated++;
} else {
// Erstelle neues Produkt
// Erstelle neues Produkt (product_first_fullscan_at = heutiges Datum)
await databases.createDocument(
databaseId,
productsCollectionId,
ID.unique(),
fullProductData
{
...fullProductData,
product_first_fullscan_at: new Date().toISOString()
}
);
created++;
}
} catch (e) {
console.error(`Fehler beim Upsert des Produkts "${platformProductId}":`, e);
// Weiter mit nächstem Produkt
// #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:'productsService.js:upsertProductsForAccount',message:'upsert error',data:{platformProductId,code:e?.code,type:e?.type,message:String(e?.message||'')},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
// #endregion
// Prüfe auf spezifische Datenbank-Fehler
if (e.code === 404 || e.type === 'collection_not_found' || e.type === 'document_not_found') {
throw new Error("Datenbank-Fehler: Products-Collection oder Dokument existiert nicht. Bitte Datenbank-Schema einrichten.");
}
if (e.code === 400 || e.message?.includes('attribute') || e.message?.includes('required')) {
throw new Error(`Datenbank-Fehler: Ein Attribut fehlt oder ist ungültig. Produkt: ${platformProductId}, Details: ${e.message}`);
}
if (e.code === 401 || e.type === 'permission_denied') {
throw new Error("Datenbank-Fehler: Keine Berechtigung zum Speichern von Produkten. Bitte Berechtigungen prüfen.");
}
// Bei anderen Fehlern: Weiter mit nächstem Produkt (nicht kritisch)
console.warn(`Überspringe Produkt "${platformProductId}" aufgrund von Fehler:`, e.message);
continue;
}
}
// #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:'productsService.js:upsertProductsForAccount',message:'upsert result',data:{created,updated},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
// #endregion
return { created, updated };
} catch (e) {
console.error("Fehler beim Upsert der Produkte:", e);

View File

@@ -0,0 +1,268 @@
# Products Collection Schema
Diese Datei beschreibt alle Attribute, die in der `products` Collection benötigt werden, damit das Programm funktioniert.
## Collection: `products`
**Collection ID:** `products` (oder über `VITE_APPWRITE_PRODUCTS_COLLECTION_ID` konfiguriert)
## Erforderliche Attribute
### 1. `product_account_id` (String, Required)
- **Typ:** String
- **Required:** Ja
- **Verwendung:**
- Filterung nach Account (Query.equal)
- Verknüpfung zu Accounts-Collection
- **Beispiel:** `"account_123"`
### 2. `product_platform` (Enum, Required)
- **Typ:** Enum
- **Required:** Ja
- **Werte:** `["amazon", "ebay"]`
- **Verwendung:**
- Speichert die Plattform (aktuell nur "ebay" wird verwendet)
- **Beispiel:** `"ebay"`
### 3. `product_platform_market` (String, Required)
- **Typ:** String
- **Required:** Ja
- **Verwendung:**
- Speichert den Marktplatz (z.B. "DE", "US", "UK")
- Wird aus Account abgeleitet
- **Beispiel:** `"DE"`, `"US"`, `"UK"`
### 4. `product_platform_product_id` (String, Required, Unique)
- **Typ:** String
- **Required:** Ja
- **Unique:** Ja (für Duplikat-Prüfung)
- **Verwendung:**
- Eindeutige Produkt-ID von der Plattform (z.B. eBay Item-ID)
- Wird für Duplikat-Prüfung verwendet
- Wird für Mapping zwischen Extension und Datenbank verwendet
- **Beispiel:** `"123456789"` (eBay Item-ID)
### 5. `product_title` (String, Optional)
- **Typ:** String
- **Required:** Nein
- **Verwendung:**
- Produkttitel
- Wird für Anzeige in UI verwendet
- Wird für Suchfilter verwendet (client-side)
- **Beispiel:** `"iPhone 13 Pro Max 256GB"`
### 6. `product_price` (Float, Optional)
- **Typ:** Float
- **Required:** Nein
- **Verwendung:**
- Produktpreis
- Wird für KPI-Berechnungen verwendet (Durchschnittspreis)
- Wird für Price Spread Insights verwendet
- **Beispiel:** `99.99`
### 7. `product_currency` (String, Optional)
- **Typ:** String
- **Required:** Nein
- **Verwendung:**
- Währung (z.B. "EUR", "USD", "GBP")
- Wird aus Market abgeleitet, falls nicht vorhanden
- **Beispiel:** `"EUR"`, `"USD"`, `"GBP"`
### 8. `product_url` (String, Optional)
- **Typ:** String
- **Required:** Nein
- **Verwendung:**
- URL zum Produkt auf der Plattform
- **Beispiel:** `"https://www.ebay.de/itm/123456789"`
### 9. `product_status` (Enum, Optional)
- **Typ:** Enum
- **Required:** Nein
- **Werte:** `["active", "ended", "unknown"]`
- **Verwendung:**
- Status des Produkts
- Wird für Filterung verwendet (Overview KPIs, Products Page)
- Wird für Status-Filter in UI verwendet
- **Default:** `"unknown"`
- **Beispiel:** `"active"`, `"ended"`, `"unknown"`
### 10. `product_category` (String, Optional)
- **Typ:** String
- **Required:** Nein
- **Verwendung:**
- Produktkategorie
- Wird für Category Share Insights verwendet
- **Default:** `"unknown"`
- **Beispiel:** `"Electronics"`, `"Clothing"`
### 11. `product_condition` (String, Optional)
- **Typ:** String
- **Required:** Nein
- **Verwendung:**
- Zustand des Produkts (z.B. "New", "Used")
- **Default:** `"unknown"`
- **Beispiel:** `"New"`, `"Used"`, `"Refurbished"`
## Standard-Appwrite-Felder
Diese Felder werden automatisch von Appwrite bereitgestellt:
- **`$id`** (String, Required) - Eindeutige Dokument-ID
- **`$createdAt`** (DateTime, Required) - Erstellungsdatum (wird für Sortierung verwendet)
- **`$updatedAt`** (DateTime, Required) - Aktualisierungsdatum
## Indexes (Empfohlen)
Für bessere Performance sollten folgende Indexes erstellt werden:
1. **Index auf `product_account_id`** (für Filterung)
- Attribute: `product_account_id`
- Typ: Key
2. **Index auf `product_platform_product_id`** (für Duplikat-Prüfung)
- Attribute: `product_platform_product_id`
- Typ: Unique Key
3. **Index auf `product_account_id` + `$createdAt`** (für Sortierung)
- Attribute: `product_account_id`, `$createdAt`
- Typ: Composite
## Berechtigungen
Die Collection benötigt folgende Berechtigungen:
- **Read:** Authenticated Users
- **Create:** Authenticated Users
- **Update:** Authenticated Users
- **Delete:** Authenticated Users (optional, falls Löschen benötigt wird)
## Appwrite CLI Befehle zum Erstellen
```bash
# Collection erstellen
appwrite databases createCollection \
--database-id eship-db \
--collection-id products \
--name "Products"
# Attribute erstellen
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_account_id \
--required true \
--size 255
appwrite databases createEnumAttribute \
--database-id eship-db \
--collection-id products \
--key product_platform \
--elements amazon ebay \
--required true
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_platform_market \
--required true \
--size 10
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_platform_product_id \
--required true \
--size 255
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_title \
--required false \
--size 500
appwrite databases createFloatAttribute \
--database-id eship-db \
--collection-id products \
--key product_price \
--required false
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_currency \
--required false \
--size 10
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_url \
--required false \
--size 1000
appwrite databases createEnumAttribute \
--database-id eship-db \
--collection-id products \
--key product_status \
--elements active ended unknown \
--required false
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_category \
--required false \
--size 255
appwrite databases createStringAttribute \
--database-id eship-db \
--collection-id products \
--key product_condition \
--required false \
--size 100
# Indexes erstellen
appwrite databases createIndex \
--database-id eship-db \
--collection-id products \
--key idx_account_id \
--type key \
--attributes product_account_id
appwrite databases createIndex \
--database-id eship-db \
--collection-id products \
--key idx_platform_product_id \
--type unique \
--attributes product_platform_product_id
appwrite databases createIndex \
--database-id eship-db \
--collection-id products \
--key idx_account_created \
--type key \
--attributes product_account_id $createdAt
```
## Zusammenfassung
**Erforderliche Attribute (Required):**
1. `product_account_id` (String)
2. `product_platform` (Enum: ["amazon", "ebay"])
3. `product_platform_market` (String)
4. `product_platform_product_id` (String, Unique)
**Optionale Attribute:**
5. `product_title` (String)
6. `product_price` (Float)
7. `product_currency` (String)
8. `product_url` (String)
9. `product_status` (Enum: ["active", "ended", "unknown"])
10. `product_category` (String)
11. `product_condition` (String)
**Standard-Felder (automatisch):**
- `$id` (String)
- `$createdAt` (DateTime)
- `$updatedAt` (DateTime)

View File

@@ -0,0 +1,78 @@
# Products Scan Fehlerbehebung
## Fehler: "Parsing failed (unknown)"
Dieser Fehler kann zwei Ursachen haben:
### 1. Extension-Fehler (Parsing failed)
**Symptome:**
- Fehlermeldung: `Extension-Fehler: Parsing failed (unknown)`
- Die Extension kann keine Produkte auf der eBay-Seite finden
**Mögliche Ursachen:**
- Die Account-URL zeigt nicht auf eine Seite mit Produkt-Listings
- Die eBay-Seite hat sich geändert und die Extension-Selektoren funktionieren nicht mehr
- Die Seite ist noch nicht vollständig geladen
**Lösung:**
- Stelle sicher, dass die Account-URL auf eine Seite mit Produkt-Listings zeigt (z.B. `/str/` Storefront oder `/usr/` Seller Profile mit Items)
- Versuche die Extension neu zu laden
- Prüfe die Browser-Konsole für weitere Details
### 2. Datenbank-Fehler (Collection/Attribute fehlt)
**Symptome:**
- Fehlermeldung: `Datenbank-Fehler: Products-Collection existiert nicht` oder
- Fehlermeldung: `Datenbank-Fehler: Ein Attribut fehlt oder ist ungültig`
**Mögliche Ursachen:**
- Die `products` Collection wurde noch nicht erstellt
- Die Collection existiert, aber es fehlen erforderliche Attribute
- Die Berechtigungen für die Collection sind nicht korrekt konfiguriert
**Lösung:**
1. **Prüfe ob die Collection existiert:**
```bash
appwrite databases listCollections --database-id eship-db
```
2. **Erstelle die Collection falls sie fehlt:**
- Öffne die Appwrite-Konsole
- Navigiere zu Databases → eship-db → Collections
- Erstelle eine neue Collection mit ID: `products`
3. **Erstelle die erforderlichen Attribute:**
Die Collection benötigt folgende Attribute:
- `product_account_id` (string, required)
- `product_platform` (enum: ["amazon", "ebay"], required)
- `product_platform_market` (string, required)
- `product_platform_product_id` (string, required, unique)
- `product_title` (string)
- `product_price` (float)
- `product_currency` (string)
- `product_url` (string)
- `product_status` (enum: ["active", "ended", "unknown"])
- `product_category` (string)
- `product_condition` (string)
4. **Prüfe die Berechtigungen:**
- Die Collection muss Lese- und Schreibrechte für authentifizierte Benutzer haben
## Fehler: "ERR_CONNECTION_REFUSED" auf Port 7242
Dieser Fehler ist **nicht kritisch** und kann ignoriert werden. Es handelt sich um einen Debug-Logging-Versuch, der fehlschlägt, weil kein Server auf Port 7242 läuft. Dies hat keinen Einfluss auf die Funktionalität.
## Diagnose-Schritte
1. **Prüfe die Browser-Konsole** für detaillierte Fehlermeldungen
2. **Prüfe ob die Extension geladen ist:**
- Öffne `chrome://extensions/`
- Stelle sicher, dass die Extension aktiviert ist
3. **Prüfe die Datenbank-Struktur:**
- Verwende die Appwrite-Konsole oder CLI
- Stelle sicher, dass die `products` Collection existiert
4. **Teste die Account-URL:**
- Öffne die Account-URL manuell im Browser
- Stelle sicher, dass Produkt-Listings sichtbar sind

View File

@@ -0,0 +1,328 @@
# PowerShell Script zum Erstellen der Products Collection
# Erstellt die Collection mit allen erforderlichen Attributen
$ErrorActionPreference = "Continue"
Write-Host "=== Products Collection Setup ===" -ForegroundColor Cyan
Write-Host ""
# Konfiguration
$DATABASE_ID = "eship-db"
$COLLECTION_ID = "products"
$COLLECTION_NAME = "Products"
# 1. Prüfe Login-Status
Write-Host "1. Prüfe Appwrite Login-Status..." -ForegroundColor Yellow
$loginCheck = appwrite databases list 2>&1
if ($LASTEXITCODE -ne 0 -and $loginCheck -like "*Session not found*") {
Write-Host " [WARNUNG] Nicht eingeloggt. Bitte zuerst einloggen:" -ForegroundColor Red
Write-Host " appwrite login" -ForegroundColor White
Write-Host ""
Write-Host " Führe diesen Befehl jetzt aus..." -ForegroundColor Yellow
appwrite login
Write-Host ""
}
# 2. Erstelle Collection
Write-Host "2. Erstelle Collection '$COLLECTION_ID'..." -ForegroundColor Yellow
$createCollection = appwrite databases createCollection `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--name $COLLECTION_NAME `
--document-security false `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] Collection '$COLLECTION_ID' erfolgreich erstellt!" -ForegroundColor Green
} else {
if ($createCollection -like "*already exists*" -or $createCollection -like "*duplicate*") {
Write-Host " [INFO] Collection '$COLLECTION_ID' existiert bereits." -ForegroundColor Yellow
} else {
Write-Host " [FEHLER] Fehler beim Erstellen der Collection:" -ForegroundColor Red
Write-Host " $createCollection" -ForegroundColor Red
exit 1
}
}
Write-Host ""
# 3. Erstelle Attribute
Write-Host "3. Erstelle Attribute..." -ForegroundColor Yellow
# 3.1 product_account_id (String, Required)
Write-Host " 3.1 product_account_id..." -ForegroundColor Gray
$attr1 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_account_id `
--required true `
--size 255 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_account_id erstellt" -ForegroundColor Green
} else {
if ($attr1 -like "*already exists*" -or $attr1 -like "*duplicate*") {
Write-Host " [INFO] product_account_id existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr1" -ForegroundColor Yellow
}
}
# 3.2 product_platform (Enum, Required)
Write-Host " 3.2 product_platform..." -ForegroundColor Gray
$attr2 = appwrite databases createEnumAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_platform `
--elements amazon ebay `
--required true `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_platform erstellt" -ForegroundColor Green
} else {
if ($attr2 -like "*already exists*" -or $attr2 -like "*duplicate*") {
Write-Host " [INFO] product_platform existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr2" -ForegroundColor Yellow
}
}
# 3.3 product_platform_market (String, Required)
Write-Host " 3.3 product_platform_market..." -ForegroundColor Gray
$attr3 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_platform_market `
--required true `
--size 10 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_platform_market erstellt" -ForegroundColor Green
} else {
if ($attr3 -like "*already exists*" -or $attr3 -like "*duplicate*") {
Write-Host " [INFO] product_platform_market existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr3" -ForegroundColor Yellow
}
}
# 3.4 product_platform_product_id (String, Required)
Write-Host " 3.4 product_platform_product_id..." -ForegroundColor Gray
$attr4 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_platform_product_id `
--required true `
--size 255 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_platform_product_id erstellt" -ForegroundColor Green
} else {
if ($attr4 -like "*already exists*" -or $attr4 -like "*duplicate*") {
Write-Host " [INFO] product_platform_product_id existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr4" -ForegroundColor Yellow
}
}
# 3.5 product_title (String, Optional)
Write-Host " 3.5 product_title..." -ForegroundColor Gray
$attr5 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_title `
--required false `
--size 500 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_title erstellt" -ForegroundColor Green
} else {
if ($attr5 -like "*already exists*" -or $attr5 -like "*duplicate*") {
Write-Host " [INFO] product_title existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr5" -ForegroundColor Yellow
}
}
# 3.6 product_price (Float, Optional)
Write-Host " 3.6 product_price..." -ForegroundColor Gray
$attr6 = appwrite databases createFloatAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_price `
--required false `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_price erstellt" -ForegroundColor Green
} else {
if ($attr6 -like "*already exists*" -or $attr6 -like "*duplicate*") {
Write-Host " [INFO] product_price existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr6" -ForegroundColor Yellow
}
}
# 3.7 product_currency (String, Optional)
Write-Host " 3.7 product_currency..." -ForegroundColor Gray
$attr7 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_currency `
--required false `
--size 10 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_currency erstellt" -ForegroundColor Green
} else {
if ($attr7 -like "*already exists*" -or $attr7 -like "*duplicate*") {
Write-Host " [INFO] product_currency existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr7" -ForegroundColor Yellow
}
}
# 3.8 product_url (String, Optional)
Write-Host " 3.8 product_url..." -ForegroundColor Gray
$attr8 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_url `
--required false `
--size 1000 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_url erstellt" -ForegroundColor Green
} else {
if ($attr8 -like "*already exists*" -or $attr8 -like "*duplicate*") {
Write-Host " [INFO] product_url existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr8" -ForegroundColor Yellow
}
}
# 3.9 product_status (Enum, Optional)
Write-Host " 3.9 product_status..." -ForegroundColor Gray
$attr9 = appwrite databases createEnumAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_status `
--elements active ended unknown `
--required false `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_status erstellt" -ForegroundColor Green
} else {
if ($attr9 -like "*already exists*" -or $attr9 -like "*duplicate*") {
Write-Host " [INFO] product_status existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr9" -ForegroundColor Yellow
}
}
# 3.10 product_category (String, Optional)
Write-Host " 3.10 product_category..." -ForegroundColor Gray
$attr10 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_category `
--required false `
--size 255 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_category erstellt" -ForegroundColor Green
} else {
if ($attr10 -like "*already exists*" -or $attr10 -like "*duplicate*") {
Write-Host " [INFO] product_category existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr10" -ForegroundColor Yellow
}
}
# 3.11 product_condition (String, Optional)
Write-Host " 3.11 product_condition..." -ForegroundColor Gray
$attr11 = appwrite databases createStringAttribute `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key product_condition `
--required false `
--size 100 `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] product_condition erstellt" -ForegroundColor Green
} else {
if ($attr11 -like "*already exists*" -or $attr11 -like "*duplicate*") {
Write-Host " [INFO] product_condition existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $attr11" -ForegroundColor Yellow
}
}
Write-Host ""
Write-Host "4. Erstelle Indexes..." -ForegroundColor Yellow
# 4.1 Index auf product_account_id
Write-Host " 4.1 Index auf product_account_id..." -ForegroundColor Gray
$idx1 = appwrite databases createIndex `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key idx_account_id `
--type key `
--attributes product_account_id `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] Index idx_account_id erstellt" -ForegroundColor Green
} else {
if ($idx1 -like "*already exists*" -or $idx1 -like "*duplicate*") {
Write-Host " [INFO] Index idx_account_id existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $idx1" -ForegroundColor Yellow
}
}
# 4.2 Unique Index auf product_platform_product_id
Write-Host " 4.2 Unique Index auf product_platform_product_id..." -ForegroundColor Gray
$idx2 = appwrite databases createIndex `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key idx_platform_product_id `
--type unique `
--attributes product_platform_product_id `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] Index idx_platform_product_id erstellt" -ForegroundColor Green
} else {
if ($idx2 -like "*already exists*" -or $idx2 -like "*duplicate*") {
Write-Host " [INFO] Index idx_platform_product_id existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $idx2" -ForegroundColor Yellow
}
}
# 4.3 Composite Index auf product_account_id + $createdAt
Write-Host " 4.3 Composite Index auf product_account_id + `$createdAt..." -ForegroundColor Gray
$idx3 = appwrite databases createIndex `
--database-id $DATABASE_ID `
--collection-id $COLLECTION_ID `
--key idx_account_created `
--type key `
--attributes product_account_id `$createdAt `
2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] Index idx_account_created erstellt" -ForegroundColor Green
} else {
if ($idx3 -like "*already exists*" -or $idx3 -like "*duplicate*") {
Write-Host " [INFO] Index idx_account_created existiert bereits" -ForegroundColor Yellow
} else {
Write-Host " [WARNUNG] $idx3" -ForegroundColor Yellow
}
}
Write-Host ""
Write-Host "=== Setup abgeschlossen ===" -ForegroundColor Green
Write-Host ""
Write-Host "Nächste Schritte:" -ForegroundColor Cyan
Write-Host "1. Prüfe die Berechtigungen in der Appwrite-Konsole" -ForegroundColor White
Write-Host "2. Stelle sicher, dass authentifizierte Benutzer Read/Write-Rechte haben" -ForegroundColor White
Write-Host "3. Teste die Collection mit einem Produkt-Scan" -ForegroundColor White
Write-Host ""