refactor: migracja wywołań API przeglądarki do abstrakcji browserAPI #127

Open
am0 wants to merge 4 commits from refactor/build_time_abstraction into develop
Collaborator

Zmigrowano wszystkie bezpośrednie wywołania browser.* API do zunifikowanej abstrakcji browserAPI, umożliwiając budowanie rozszerzenia zarówno dla Firefox (browser.browserAction) jak i Chrome (chrome.action) z jednego kodu źródłowego.

Zmigrowane pliki aplikacji (4):

1. memory.ts

Dodano import:

  • import browserAPI from ./lib/browser-api

Zastąpiono wywołania API:

  • browser.browserAction.setBadgeText → browserAPI.badge.setBadgeText
  • browser.browserAction.setTitle → browserAPI.badge.setTitle
  • browser.browserAction.setBadgeBackgroundColor → browserAPI.badge.setBadgeBackgroundColor
  • browser.webRequest.onBeforeRequest.addListener → browserAPI.webRequest.onBeforeRequest.addListener
  • browser.webRequest.onBeforeSendHeaders.addListener → browserAPI.webRequest.onBeforeSendHeaders.addListener
  • browser.cookies.getAll → browserAPI.cookies.getAll
  • browser.cookies.remove → browserAPI.cookies.remove
  • browser.extension.getBackgroundPage() → browserAPI.extension.getBackgroundPage()

Dodano obsługę null:

  • Funkcja getMemory() sprawdza teraz czy getBackgroundPage() nie zwraca null

2. components/toolbar/toolbar.tsx

Dodano import:

  • import browserAPI from ../../lib/browser-api

Zastąpiono wywołania API:

  • browser.tabs.query → browserAPI.tabs.query
  • browser.windows.WINDOW_ID_CURRENT → browserAPI.windows.WINDOW_ID_CURRENT
  • browser.tabs.onUpdated.addListener → browserAPI.tabs.onUpdated.addListener
  • browser.tabs.onUpdated.removeListener → browserAPI.tabs.onUpdated.removeListener

Zachowano całą funkcjonalność:

  • Wszystkie sekcje UI (header, summary z licznikami, details, about, actions)
  • Wszystkie hooki React i logika biznesowa
  • Funkcje pomocnicze (getCurrentTab, isDomainHighlySuspicious, autoMark)

3. components/tab-dropdown.tsx

Zmieniono importy:

  • Usunięto: import { Tab } from ../../util
  • Dodano: import browserAPI, { Tab } from ../../lib/browser-api

Zastąpiono wywołania API:

  • browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true })

Poprawka typów:

  • Typ Tab teraz pochodzi z browserAPI, zapewniając zgodność typów

4. util.ts

Dodano import:

  • import browserAPI from ./lib/browser-api

Zastąpiono wywołania API:

  • Typ Tab pochodzi teraz z browserAPI.tabs.query zamiast browser.tabs.query
  • browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true }) w funkcji getTabByID

Zachowano wszystkie funkcje:

  • getshorthost, useEmitter, parseCookie, getTabByID
  • parseToObject, isJSONObject, isURL, hyphenate, unique
  • allSubhosts, reduceConcat, getDate, toBase64, makeThrottle
  • isSameURL, isBase64, isBase64JSON
  • flattenObject, flattenObjectEntries
  • maskString, safeDecodeURIComponent, normalizeForClassname
  • wordlist, dataLocationToText, downloadText

Rozszerzenie abstrakcji browserAPI:

lib/browser-api/types.ts

Dlaczego rozszerzono:
Początkowy minimalny interfejs RequestDetails był niewystarczający, ponieważ brakowało kluczowych właściwości wymaganych przez konstruktor ExtendedRequest. Gdy listenery webRequest są wywoływane, przekazują kompletny obiekt Request do ExtendedRequest, a nie tylko podstawowe szczegóły.

Co zostało dodane:
Pełny typ Request z util.ts, zawierający:

  • Właściwości główne: requestId, tabId, url, method, type
  • Nawigacja ramek: frameId, parentFrameId, documentUrl, originUrl
  • Opcjonalne metadane: cookieStoreId, incognito, thirdParty, timeStamp
  • Szczegóły żądania: requestHeaders, urlClassification, proxyInfo

Przyczyna źródłowa błędów TypeScript:
Konstruktor ExtendedRequest oczekiwał właściwości takich jak frameId, method,
originUrl, parentFrameId, documentUrl, urlClassification, etc. Minimalny
interfejs powodował błędy:

  • Argument of type RequestDetails is not assignable to parameter of type Request
  • Type RequestDetails is missing properties: frameId, method, originUrl, parentFrameId, and 4 more

Rozwiązanie:
Używając pełnej definicji typu Request, abstrakcja browserAPI poprawnie typuje callbacki webRequest, zapewniając bezpieczeństwo typów zarówno dla buildu Firefox jak i Chrome, przy zachowaniu kompatybilności z istniejącą implementacją ExtendedRequest.

Zmiana w RequestListener:

  • Było: (details: RequestDetails) => void
  • Jest: (details: Request) => void

Wpływ zmian:

  • memory.ts, toolbar.tsx, tab-dropdown.tsx, util.ts działają z TARGET=firefox i TARGET=chrome
  • Zachowano bezpieczeństwo typów w całym kodzie
  • Brak zmian funkcjonalnych - tylko warstwa abstrakcji
  • Gotowość do kompatybilności z Chrome Manifest V3 (chrome.action vs browser.browserAction)

Następne kroki:

  • Aktualizacja esbuild.config.js dla budowania z TARGET=chrome do dist-chrome/
  • Aktualizacja manifestu Chrome zgodnie z regułami Manifest v3
  • Skrypt konwertujący SVG na PNG dla Chrome
  • Testowanie rozszerzenia w przeglądarce Chrome
Zmigrowano wszystkie bezpośrednie wywołania browser.* API do zunifikowanej abstrakcji browserAPI, umożliwiając budowanie rozszerzenia zarówno dla Firefox (browser.browserAction) jak i Chrome (chrome.action) z jednego kodu źródłowego. ## Zmigrowane pliki aplikacji (4): ### 1. memory.ts Dodano import: - import browserAPI from ./lib/browser-api Zastąpiono wywołania API: - browser.browserAction.setBadgeText → browserAPI.badge.setBadgeText - browser.browserAction.setTitle → browserAPI.badge.setTitle - browser.browserAction.setBadgeBackgroundColor → browserAPI.badge.setBadgeBackgroundColor - browser.webRequest.onBeforeRequest.addListener → browserAPI.webRequest.onBeforeRequest.addListener - browser.webRequest.onBeforeSendHeaders.addListener → browserAPI.webRequest.onBeforeSendHeaders.addListener - browser.cookies.getAll → browserAPI.cookies.getAll - browser.cookies.remove → browserAPI.cookies.remove - browser.extension.getBackgroundPage() → browserAPI.extension.getBackgroundPage() Dodano obsługę null: - Funkcja getMemory() sprawdza teraz czy getBackgroundPage() nie zwraca null ### 2. components/toolbar/toolbar.tsx Dodano import: - import browserAPI from ../../lib/browser-api Zastąpiono wywołania API: - browser.tabs.query → browserAPI.tabs.query - browser.windows.WINDOW_ID_CURRENT → browserAPI.windows.WINDOW_ID_CURRENT - browser.tabs.onUpdated.addListener → browserAPI.tabs.onUpdated.addListener - browser.tabs.onUpdated.removeListener → browserAPI.tabs.onUpdated.removeListener Zachowano całą funkcjonalność: - Wszystkie sekcje UI (header, summary z licznikami, details, about, actions) - Wszystkie hooki React i logika biznesowa - Funkcje pomocnicze (getCurrentTab, isDomainHighlySuspicious, autoMark) ### 3. components/tab-dropdown.tsx Zmieniono importy: - Usunięto: import { Tab } from ../../util - Dodano: import browserAPI, { Tab } from ../../lib/browser-api Zastąpiono wywołania API: - browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true }) Poprawka typów: - Typ Tab teraz pochodzi z browserAPI, zapewniając zgodność typów ### 4. util.ts Dodano import: - import browserAPI from ./lib/browser-api Zastąpiono wywołania API: - Typ Tab pochodzi teraz z browserAPI.tabs.query zamiast browser.tabs.query - browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true }) w funkcji getTabByID Zachowano wszystkie funkcje: - getshorthost, useEmitter, parseCookie, getTabByID - parseToObject, isJSONObject, isURL, hyphenate, unique - allSubhosts, reduceConcat, getDate, toBase64, makeThrottle - isSameURL, isBase64, isBase64JSON - flattenObject, flattenObjectEntries - maskString, safeDecodeURIComponent, normalizeForClassname - wordlist, dataLocationToText, downloadText ## Rozszerzenie abstrakcji browserAPI: ### lib/browser-api/types.ts Dlaczego rozszerzono: Początkowy minimalny interfejs RequestDetails był niewystarczający, ponieważ brakowało kluczowych właściwości wymaganych przez konstruktor ExtendedRequest. Gdy listenery webRequest są wywoływane, przekazują kompletny obiekt Request do ExtendedRequest, a nie tylko podstawowe szczegóły. Co zostało dodane: Pełny typ Request z util.ts, zawierający: - Właściwości główne: requestId, tabId, url, method, type - Nawigacja ramek: frameId, parentFrameId, documentUrl, originUrl - Opcjonalne metadane: cookieStoreId, incognito, thirdParty, timeStamp - Szczegóły żądania: requestHeaders, urlClassification, proxyInfo Przyczyna źródłowa błędów TypeScript: Konstruktor ExtendedRequest oczekiwał właściwości takich jak frameId, method, originUrl, parentFrameId, documentUrl, urlClassification, etc. Minimalny interfejs powodował błędy: - Argument of type RequestDetails is not assignable to parameter of type Request - Type RequestDetails is missing properties: frameId, method, originUrl, parentFrameId, and 4 more Rozwiązanie: Używając pełnej definicji typu Request, abstrakcja browserAPI poprawnie typuje callbacki webRequest, zapewniając bezpieczeństwo typów zarówno dla buildu Firefox jak i Chrome, przy zachowaniu kompatybilności z istniejącą implementacją ExtendedRequest. Zmiana w RequestListener: - Było: (details: RequestDetails) => void - Jest: (details: Request) => void ## Wpływ zmian: - memory.ts, toolbar.tsx, tab-dropdown.tsx, util.ts działają z TARGET=firefox i TARGET=chrome - Zachowano bezpieczeństwo typów w całym kodzie - Brak zmian funkcjonalnych - tylko warstwa abstrakcji - Gotowość do kompatybilności z Chrome Manifest V3 (chrome.action vs browser.browserAction) ## Następne kroki: - Aktualizacja esbuild.config.js dla budowania z TARGET=chrome do dist-chrome/ - Aktualizacja manifestu Chrome zgodnie z regułami Manifest v3 - Skrypt konwertujący SVG na PNG dla Chrome - Testowanie rozszerzenia w przeglądarce Chrome
am0 added 1 commit 2025-09-30 12:22:50 +02:00
Zmigrowano wszystkie bezpośrednie wywołania browser.* API do zunifikowanej abstrakcji browserAPI, umożliwiając budowanie rozszerzenia zarówno dla Firefox (browser.browserAction) jak i Chrome (chrome.action) z jednego kodu źródłowego.

## Zmigrowane pliki aplikacji (4):

### 1. memory.ts
Dodano import:
- import browserAPI from ./lib/browser-api

Zastąpiono wywołania API:
- browser.browserAction.setBadgeText → browserAPI.badge.setBadgeText
- browser.browserAction.setTitle → browserAPI.badge.setTitle
- browser.browserAction.setBadgeBackgroundColor → browserAPI.badge.setBadgeBackgroundColor
- browser.webRequest.onBeforeRequest.addListener → browserAPI.webRequest.onBeforeRequest.addListener
- browser.webRequest.onBeforeSendHeaders.addListener → browserAPI.webRequest.onBeforeSendHeaders.addListener
- browser.cookies.getAll → browserAPI.cookies.getAll
- browser.cookies.remove → browserAPI.cookies.remove
- browser.extension.getBackgroundPage() → browserAPI.extension.getBackgroundPage()

Dodano obsługę null:
- Funkcja getMemory() sprawdza teraz czy getBackgroundPage() nie zwraca null

### 2. components/toolbar/toolbar.tsx
Dodano import:
- import browserAPI from ../../lib/browser-api

Zastąpiono wywołania API:
- browser.tabs.query → browserAPI.tabs.query
- browser.windows.WINDOW_ID_CURRENT → browserAPI.windows.WINDOW_ID_CURRENT
- browser.tabs.onUpdated.addListener → browserAPI.tabs.onUpdated.addListener
- browser.tabs.onUpdated.removeListener → browserAPI.tabs.onUpdated.removeListener

Zachowano całą funkcjonalność:
- Wszystkie sekcje UI (header, summary z licznikami, details, about, actions)
- Wszystkie hooki React i logika biznesowa
- Funkcje pomocnicze (getCurrentTab, isDomainHighlySuspicious, autoMark)

### 3. components/tab-dropdown.tsx
Zmieniono importy:
- Usunięto: import { Tab } from ../../util
- Dodano: import browserAPI, { Tab } from ../../lib/browser-api

Zastąpiono wywołania API:
- browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true })

Poprawka typów:
- Typ Tab teraz pochodzi z browserAPI, zapewniając zgodność typów

### 4. util.ts
Dodano import:
- import browserAPI from ./lib/browser-api

Zastąpiono wywołania API:
- Typ Tab pochodzi teraz z browserAPI.tabs.query zamiast browser.tabs.query
- browser.tabs.query({ currentWindow: true }) → browserAPI.tabs.query({ currentWindow: true }) w funkcji getTabByID

Zachowano wszystkie funkcje:
- getshorthost, useEmitter, parseCookie, getTabByID
- parseToObject, isJSONObject, isURL, hyphenate, unique
- allSubhosts, reduceConcat, getDate, toBase64, makeThrottle
- isSameURL, isBase64, isBase64JSON
- flattenObject, flattenObjectEntries
- maskString, safeDecodeURIComponent, normalizeForClassname
- wordlist, dataLocationToText, downloadText

## Rozszerzenie abstrakcji browserAPI:

### lib/browser-api/types.ts
Dlaczego rozszerzono:
Początkowy minimalny interfejs RequestDetails był niewystarczający, ponieważ brakowało kluczowych właściwości wymaganych przez konstruktor ExtendedRequest. Gdy listenery webRequest są wywoływane, przekazują kompletny obiekt Request do ExtendedRequest, a nie tylko podstawowe szczegóły.

Co zostało dodane:
Pełny typ Request z util.ts, zawierający:
- Właściwości główne: requestId, tabId, url, method, type
- Nawigacja ramek: frameId, parentFrameId, documentUrl, originUrl
- Opcjonalne metadane: cookieStoreId, incognito, thirdParty, timeStamp
- Szczegóły żądania: requestHeaders, urlClassification, proxyInfo

Przyczyna źródłowa błędów TypeScript:
Konstruktor ExtendedRequest oczekiwał właściwości takich jak frameId, method,
originUrl, parentFrameId, documentUrl, urlClassification, etc. Minimalny
interfejs powodował błędy:
- Argument of type RequestDetails is not assignable to parameter of type Request
- Type RequestDetails is missing properties: frameId, method, originUrl, parentFrameId, and 4 more

Rozwiązanie:
Używając pełnej definicji typu Request, abstrakcja browserAPI poprawnie typuje callbacki webRequest, zapewniając bezpieczeństwo typów zarówno dla buildu Firefox jak i Chrome, przy zachowaniu kompatybilności z istniejącą implementacją ExtendedRequest.

Zmiana w RequestListener:
- Było: (details: RequestDetails) => void
- Jest: (details: Request) => void

## Wpływ zmian:
- memory.ts, toolbar.tsx, tab-dropdown.tsx, util.ts działają z TARGET=firefox i TARGET=chrome
- Zachowano bezpieczeństwo typów w całym kodzie
- Brak zmian funkcjonalnych - tylko warstwa abstrakcji
- Gotowość do kompatybilności z Chrome Manifest V3 (chrome.action vs browser.browserAction)

## Następne kroki:
- Aktualizacja esbuild.config.js dla budowania z TARGET=chrome do dist-chrome/
- Aktualizacja manifestu Chrome zgodnie z regułami Manifest v3
- Skrypt konwertujący SVG na PNG dla Chrome
- Testowanie rozszerzenia w przeglądarce Chrome
am0 added 1 commit 2025-10-18 13:08:47 +02:00
## 🎯 Cel
Dodanie pełnego wsparcia dla Chrome Manifest V3 przy zachowaniu kompatybilności z Firefox. Główne wyzwanie: Chrome MV3 używa service workerów zamiast persistent background pages, co wymaga nowej architektury zarządzania pamięcią.

---

## 🏗️ Architektura

### Nowa warstwa abstrakcji: lib/browser-api/

**lib/browser-api/index.ts**
- Główny punkt wejścia do zunifikowanego API
- Wybiera właściwą implementację na podstawie zmiennej TARGET (build-time)
- Eksportuje jeden interfejs dla całej aplikacji

**lib/browser-api/types.ts**
- Wspólne definicje typów dla obu przeglądarek
- Interfejs BrowserAPI definiujący wszystkie potrzebne metody
- Typy dla tabs, badge, webRequest, cookies, extension, windows

**lib/browser-api/firefox.ts**
- Adapter dla Firefox browser.* API
- Lazy access do globalnego obiektu browser (bezpieczne dla środowisk bez Firefox API)
- Wszystkie metody zwracają Promise lub są no-op jeśli API niedostępne

**lib/browser-api/chrome.ts**
- Adapter dla Chrome chrome.* API
- Mapowanie chrome.action → badge (różnica nazewnictwa)
- Ochrona przed błędami gdy karta zostaje zamknięta (try-catch w operacjach badge)

---

## 🔧 Build System

### esbuild.config.js
- **Dodano**: Rozpoznawanie zmiennej środowiskowej TARGET (firefox/chrome)
- **Dodano**: Różne katalogi wyjściowe (dist-firefox, dist-chrome)
- **Dodano**: Kopiowanie odpowiedniego manifestu na podstawie TARGET
- **Dodano**: Plugin do konwersji ikon SVG → PNG dla Chrome (wymaga PNG w MV3)
- **Zmieniono**: define zawiera teraz process.env.TARGET dostępny w runtime

### package.json
- **Dodano**: Skrypty build:firefox, build:chrome, watch:firefox, watch:chrome
- **Dodano**: Skrypty build-addon:firefox, build-addon:chrome do tworzenia paczek
- **Dodano**: Skrypt convert-icons do generowania PNG z SVG
- **Dodano**: Zależność sharp do konwersji obrazów

### scripts/convert-icons.js (NOWY PLIK)
- Konwertuje assets/icon-addon.svg → PNG w rozmiarach 16, 32, 48, 128px
- Wymagane dla Chrome (MV3 nie akceptuje SVG w manifestach)

### manifest-chrome.json (NOWY PLIK)
- Manifest V3 dla Chrome
- background.service_worker zamiast background.scripts
- action zamiast browser_action
- Ikony PNG zamiast SVG
- host_permissions zamiast embedowanych w permissions

---

## 🧠 Pamięć i Stan (NAJWIĘKSZA ZMIANA)

### memory.ts - Kompletna refaktoryzacja

**Problem Chrome MV3:**
- Service worker może być wyładowany w dowolnym momencie
- Brak dostępu do window.memory z popup/sidebar
- chrome.extension.getBackgroundPage() zwraca null w MV3

**Rozwiązanie:**
1. **Service Worker**: Trzyma pełne dane, synchronizuje do chrome.storage.session
2. **Popup/Sidebar**: Tworzy własną instancję Memory czytając z storage
3. **Throttled sync**: Maksymalnie co 500ms zapisy do storage (wydajność)

**Nowa klasa: CachedRequestCluster**
- Dziedziczy po RequestCluster ale NIE ma rzeczywistych requestów
- Przechowuje tylko metadane: hasCookies, exposesOrigin, hasMarks
- Implementuje wszystkie wymagane metody zwracając cached state
- Używana TYLKO w popup/report window w Chrome

**Zmiany w Memory klasie:**
- **Dodano**: isReady flag i readyPromise dla async inicjalizacji (Chrome)
- **Dodano**: waitUntilReady() - popup musi poczekać na załadowanie danych
- **Dodano**: tabUrls: Map<number, string> - tracking pełnych URL dla Chrome (service worker nie dostaje documentUrl)
- **Dodano**: scheduleSyncToStorage() - throttled sync do storage
- **Dodano**: syncToStorage() - serializacja clustrów do JSON
- **Dodano**: loadFromStorage() - deserializacja przy starcie popup
- **Zmieniono**: register() śledzi main_frame URL i synuje po każdej zmianie
- **Zmieniono**: Badge operacje w try-catch (karta może być zamknięta)

**Funkcja getMemory():**
- **Firefox**: browserAPI.extension.getBackgroundPage().memory (tradycyjnie)
- **Chrome Service Worker**: self.memory (jesteśmy W service workerze)
- **Chrome Popup**: Tworzy NOWĄ instancję czytając z storage (cachowana jako popupMemoryInstance)

---

## 🔒 Bezpieczeństwo i Obsługa Błędów

### util.ts - getshorthost()
- **Dodano**: Walidacja wejścia (null, undefined, pusty string)
- **Dodano**: Czyszczenie URL (protokół, ścieżka, port)
- **Dodano**: Obsługa edge cases (localhost, single word domains)
- **Dodano**: Bezpieczne fallbacki zamiast crashowania
- **Dodano**: Console.warn zamiast milczących błędów

### extended-request.ts
- **MASYWNE POPRAWKI** parsowania URL w konstruktorze
- **Dodano**: isValidHttpUrl() helper - sprawdza czy URL zaczyna się od http(s)
- **Dodano**: safeParseUrl() helper - try-catch wokół new URL()
- **Dodano**: Próba parsowania wielu URL w kolejności priorytetów
- **Dodano**: Obsługa Chrome MV3 initiator property
- **Dodano**: Bezpieczne defaulty gdy parsowanie się nie uda (unknown://unknown)
- **Zmieniono**: isThirdParty() pomija requesty z unparseable URLs
- **Dodano**: uint8ArrayToString() - chunked konwersja dużych arrayów (zapobiega stack overflow)
- **Zmieniono**: Request body processing używa chunked konwersji

---

## 🎨 UI Components

### toolbar.tsx (popup)
- **Dodano**: getCurrentTab() z retry mechanism (Chrome czasem nie zwraca karty od razu)
- **Dodano**: Sprawdzanie memoryReady przed renderowaniem danych
- **Dodano**: Wywołanie waitUntilReady() w useEffect
- **Dodano**: Opóźnienie 200ms dla Chrome przy inicjalizacji (service worker + storage delay)
- **Dodano**: Graceful handling gdy popup otwarty bez active tab

### sidebar.tsx
- **Dodano**: Stan memoryReady i loading screen dla Chrome
- **Dodano**: Wywołanie waitUntilReady() przed dostępem do danych
- **Dodano**: Conditional rendering - pokazuje Ładowanie... gdy pamięć nie gotowa

### report-window.tsx
- **Dodano**: Stan memoryReady i loading message
- **Dodano**: Wywołanie waitUntilReady() przed generowaniem raportu
- **Dodano**: Fallback konstruowania URL z origin gdy brak visited_url
- **Zmieniono**: Filtr clustrów używa hasMarks() zamiast getMarkedRequests().length

### stolen-data-cluster.tsx
- **Bez znaczących zmian** - działa z abstrakcją RequestCluster

---

## 🐛 Poprawki Bugów

### background.ts
- **Dodano**: Diagnostic logging do debugowania inicjalizacji
- **Dodano**: Try-catch wokół init() z error logging
- **Dodano**: Różne logi dla Firefox vs Chrome

### memory.ts - badge operations
- **Dodano**: Try-catch wokół wszystkich operacji badge
- Zapobiega crashowaniu gdy użytkownik zamknie kartę podczas operacji

### chrome.ts - badge adapter
- **Dodano**: Try-catch w setBadgeText, setTitle, setBadgeBackgroundColor
- Chrome rzuca błędy gdy operujemy na zamkniętych kartach

---

## 📝 Workflow Użytkownika (Chrome)

1. **Użytkownik odwiedza stronę** → Service worker rejestruje requesty → Auto-mark podejrzanych → Sync do storage
2. **Użytkownik otwiera popup** → Tworzy Memory → Czyta ze storage → Pokazuje dane z flagami
3. **Użytkownik (od)zaznacza domeny** → Zmienia flagi → Sync do storage
4. **Użytkownik generuje raport** → Otwiera report-window → Czyta ze storage → Filtruje według hasMarks()

---

##  Rezultat

-  **Firefox**: Działa jak wcześniej (background page + window.memory)
-  **Chrome**: Pełne wsparcie MV3 (service worker + storage.session)
-  **Wspólny kod**: 95% kodu jest shared, tylko warstwa dostępu do API różni się
-  **Bezpieczeństwo**: Obsługa wszystkich edge cases w parsowaniu URL
-  **Wydajność**: Throttled sync do storage (max co 500ms)
-  **UX**: Loading states w popup/sidebar dla Chrome
-  **Build**: npm run build-addon:firefox lub npm build-addon dla firefox / npm run build:chrome dla chrome
Author
Collaborator

Dodałem prawdopodobnie ostatni, bo pełny commit. Tak, dużo plików ale wcale nie tak dużo zmian. Logika działania pozostaje z grubsza taka sama, zmiany dot. użycia narzędzi specyficznych dla przeglądarki - Chrome jest MOCNO inny od Firefoxa. Wrzucam tu jeszcze pełny commit z lepszym formatowaniem dla czytelności.

feat/refactor: Chrome MV3 Support + Refaktoryzacja architektury dla kompatybilności obu przeglądarek

🎯 Cel

Dodanie pełnego wsparcia dla Chrome Manifest V3 przy zachowaniu kompatybilności z Firefox. Główne wyzwanie: Chrome MV3 używa service workerów zamiast persistent background pages, co wymaga nowej architektury zarządzania pamięcią.


🏗️ Architektura

Nowa warstwa abstrakcji: lib/browser-api/

lib/browser-api/index.ts

  • Główny punkt wejścia do zunifikowanego API
  • Wybiera właściwą implementację na podstawie zmiennej TARGET (build-time)
  • Eksportuje jeden interfejs dla całej aplikacji

lib/browser-api/types.ts

  • Wspólne definicje typów dla obu przeglądarek
  • Interfejs BrowserAPI definiujący wszystkie potrzebne metody
  • Typy dla tabs, badge, webRequest, cookies, extension, windows

lib/browser-api/firefox.ts

  • Adapter dla Firefox browser.* API
  • Lazy access do globalnego obiektu browser (bezpieczne dla środowisk bez Firefox API)
  • Wszystkie metody zwracają Promise lub są no-op jeśli API niedostępne

lib/browser-api/chrome.ts

  • Adapter dla Chrome chrome.* API
  • Mapowanie chrome.action → badge (różnica nazewnictwa)
  • Ochrona przed błędami gdy karta zostaje zamknięta (try-catch w operacjach badge)

🔧 Build System

esbuild.config.js

  • Dodano: Rozpoznawanie zmiennej środowiskowej TARGET (firefox/chrome)
  • Dodano: Różne katalogi wyjściowe (dist-firefox, dist-chrome)
  • Dodano: Kopiowanie odpowiedniego manifestu na podstawie TARGET
  • Dodano: Plugin do konwersji ikon SVG → PNG dla Chrome (wymaga PNG w MV3)
  • Zmieniono: define zawiera teraz process.env.TARGET dostępny w runtime

package.json

  • Dodano: Skrypty build:firefox, build:chrome, watch:firefox, watch:chrome
  • Dodano: Skrypty build-addon:firefox, build-addon:chrome do tworzenia paczek
  • Dodano: Skrypt convert-icons do generowania PNG z SVG
  • Dodano: Zależność sharp do konwersji obrazów

scripts/convert-icons.js (NOWY PLIK)

  • Konwertuje assets/icon-addon.svg → PNG w rozmiarach 16, 32, 48, 128px
  • Wymagane dla Chrome (MV3 nie akceptuje SVG w manifestach)

manifest-chrome.json (NOWY PLIK)

  • Manifest V3 dla Chrome
  • background.service_worker zamiast background.scripts
  • action zamiast browser_action
  • Ikony PNG zamiast SVG
  • host_permissions zamiast embedowanych w permissions

🧠 Pamięć i Stan (NAJWIĘKSZA ZMIANA)

memory.ts - Kompletna refaktoryzacja

Problem Chrome MV3:

  • Service worker może być wyładowany w dowolnym momencie
  • Brak dostępu do window.memory z popup/sidebar
  • chrome.extension.getBackgroundPage() zwraca null w MV3

Rozwiązanie:

  1. Service Worker: Trzyma pełne dane, synchronizuje do chrome.storage.session
  2. Popup/Sidebar: Tworzy własną instancję Memory czytając z storage
  3. Throttled sync: Maksymalnie co 500ms zapisy do storage (wydajność)

Nowa klasa: CachedRequestCluster

  • Dziedziczy po RequestCluster ale NIE ma rzeczywistych requestów
  • Przechowuje tylko metadane: hasCookies, exposesOrigin, hasMarks
  • Implementuje wszystkie wymagane metody zwracając cached state
  • Używana TYLKO w popup/report window w Chrome

Zmiany w Memory klasie:

  • Dodano: isReady flag i readyPromise dla async inicjalizacji (Chrome)
  • Dodano: waitUntilReady() - popup musi poczekać na załadowanie danych
  • Dodano: tabUrls: Map<number, string> - tracking pełnych URL dla Chrome (service worker nie dostaje documentUrl)
  • Dodano: scheduleSyncToStorage() - throttled sync do storage
  • Dodano: syncToStorage() - serializacja clustrów do JSON
  • Dodano: loadFromStorage() - deserializacja przy starcie popup
  • Zmieniono: register() śledzi main_frame URL i synuje po każdej zmianie
  • Zmieniono: Badge operacje w try-catch (karta może być zamknięta)

Funkcja getMemory():

  • Firefox: browserAPI.extension.getBackgroundPage().memory (tradycyjnie)
  • Chrome Service Worker: self.memory (jesteśmy W service workerze)
  • Chrome Popup: Tworzy NOWĄ instancję czytając z storage (cachowana jako popupMemoryInstance)

🔒 Bezpieczeństwo i Obsługa Błędów

util.ts - getshorthost()

  • Dodano: Walidacja wejścia (null, undefined, pusty string)
  • Dodano: Czyszczenie URL (protokół, ścieżka, port)
  • Dodano: Obsługa edge cases (localhost, single word domains)
  • Dodano: Bezpieczne fallbacki zamiast crashowania
  • Dodano: Console.warn zamiast milczących błędów

extended-request.ts

  • MASYWNE POPRAWKI parsowania URL w konstruktorze
  • Dodano: isValidHttpUrl() helper - sprawdza czy URL zaczyna się od http(s)
  • Dodano: safeParseUrl() helper - try-catch wokół new URL()
  • Dodano: Próba parsowania wielu URL w kolejności priorytetów
  • Dodano: Obsługa Chrome MV3 initiator property
  • Dodano: Bezpieczne defaulty gdy parsowanie się nie uda (unknown://unknown)
  • Zmieniono: isThirdParty() pomija requesty z unparseable URLs
  • Dodano: uint8ArrayToString() - chunked konwersja dużych arrayów (zapobiega stack overflow)
  • Zmieniono: Request body processing używa chunked konwersji

🎨 UI Components

toolbar.tsx (popup)

  • Dodano: getCurrentTab() z retry mechanism (Chrome czasem nie zwraca karty od razu)
  • Dodano: Sprawdzanie memoryReady przed renderowaniem danych
  • Dodano: Wywołanie waitUntilReady() w useEffect
  • Dodano: Opóźnienie 200ms dla Chrome przy inicjalizacji (service worker + storage delay)
  • Dodano: Graceful handling gdy popup otwarty bez active tab

sidebar.tsx

  • Dodano: Stan memoryReady i loading screen dla Chrome
  • Dodano: Wywołanie waitUntilReady() przed dostępem do danych
  • Dodano: Conditional rendering - pokazuje "Ładowanie..." gdy pamięć nie gotowa

report-window.tsx

  • Dodano: Stan memoryReady i loading message
  • Dodano: Wywołanie waitUntilReady() przed generowaniem raportu
  • Dodano: Fallback konstruowania URL z origin gdy brak visited_url
  • Zmieniono: Filtr clustrów używa hasMarks() zamiast getMarkedRequests().length

stolen-data-cluster.tsx

  • Bez znaczących zmian - działa z abstrakcją RequestCluster

🐛 Poprawki Bugów

background.ts

  • Dodano: Diagnostic logging do debugowania inicjalizacji
  • Dodano: Try-catch wokół init() z error logging
  • Dodano: Różne logi dla Firefox vs Chrome

memory.ts - badge operations

  • Dodano: Try-catch wokół wszystkich operacji badge
  • Zapobiega crashowaniu gdy użytkownik zamknie kartę podczas operacji

chrome.ts - badge adapter

  • Dodano: Try-catch w setBadgeText, setTitle, setBadgeBackgroundColor
  • Chrome rzuca błędy gdy operujemy na zamkniętych kartach

📝 Workflow Użytkownika (Chrome)

  1. Użytkownik odwiedza stronę → Service worker rejestruje requesty → Auto-mark podejrzanych → Sync do storage
  2. Użytkownik otwiera popup → Tworzy Memory → Czyta ze storage → Pokazuje dane z flagami
  3. Użytkownik (od)zaznacza domeny → Zmienia flagi → Sync do storage
  4. Użytkownik generuje raport → Otwiera report-window → Czyta ze storage → Filtruje według hasMarks()

Rezultat

  • Firefox: Działa jak wcześniej (background page + window.memory)
  • Chrome: Pełne wsparcie MV3 (service worker + storage.session)
  • Wspólny kod: 95% kodu jest shared, tylko warstwa dostępu do API różni się
  • Bezpieczeństwo: Obsługa wszystkich edge cases w parsowaniu URL
  • Wydajność: Throttled sync do storage (max co 500ms)
  • UX: Loading states w popup/sidebar dla Chrome
  • Build: npm run build-addon:firefox lub npm build-addon dla firefox / npm run build:chrome dla chrome
Dodałem prawdopodobnie ostatni, bo pełny commit. Tak, dużo plików ale wcale nie tak dużo zmian. Logika działania pozostaje z grubsza taka sama, zmiany dot. użycia narzędzi specyficznych dla przeglądarki - Chrome jest MOCNO inny od Firefoxa. Wrzucam tu jeszcze pełny commit z lepszym formatowaniem dla czytelności. # feat/refactor: Chrome MV3 Support + Refaktoryzacja architektury dla kompatybilności obu przeglądarek ## 🎯 Cel Dodanie pełnego wsparcia dla Chrome Manifest V3 przy zachowaniu kompatybilności z Firefox. Główne wyzwanie: Chrome MV3 używa service workerów zamiast persistent background pages, co wymaga nowej architektury zarządzania pamięcią. --- ## 🏗️ Architektura ### Nowa warstwa abstrakcji: lib/browser-api/ **lib/browser-api/index.ts** - Główny punkt wejścia do zunifikowanego API - Wybiera właściwą implementację na podstawie zmiennej TARGET (build-time) - Eksportuje jeden interfejs dla całej aplikacji **lib/browser-api/types.ts** - Wspólne definicje typów dla obu przeglądarek - Interfejs BrowserAPI definiujący wszystkie potrzebne metody - Typy dla tabs, badge, webRequest, cookies, extension, windows **lib/browser-api/firefox.ts** - Adapter dla Firefox browser.* API - Lazy access do globalnego obiektu browser (bezpieczne dla środowisk bez Firefox API) - Wszystkie metody zwracają Promise lub są no-op jeśli API niedostępne **lib/browser-api/chrome.ts** - Adapter dla Chrome chrome.* API - Mapowanie chrome.action → badge (różnica nazewnictwa) - Ochrona przed błędami gdy karta zostaje zamknięta (try-catch w operacjach badge) --- ## 🔧 Build System ### esbuild.config.js - **Dodano**: Rozpoznawanie zmiennej środowiskowej TARGET (firefox/chrome) - **Dodano**: Różne katalogi wyjściowe (dist-firefox, dist-chrome) - **Dodano**: Kopiowanie odpowiedniego manifestu na podstawie TARGET - **Dodano**: Plugin do konwersji ikon SVG → PNG dla Chrome (wymaga PNG w MV3) - **Zmieniono**: define zawiera teraz process.env.TARGET dostępny w runtime ### package.json - **Dodano**: Skrypty build:firefox, build:chrome, watch:firefox, watch:chrome - **Dodano**: Skrypty build-addon:firefox, build-addon:chrome do tworzenia paczek - **Dodano**: Skrypt convert-icons do generowania PNG z SVG - **Dodano**: Zależność sharp do konwersji obrazów ### scripts/convert-icons.js (NOWY PLIK) - Konwertuje assets/icon-addon.svg → PNG w rozmiarach 16, 32, 48, 128px - Wymagane dla Chrome (MV3 nie akceptuje SVG w manifestach) ### manifest-chrome.json (NOWY PLIK) - Manifest V3 dla Chrome - background.service_worker zamiast background.scripts - action zamiast browser_action - Ikony PNG zamiast SVG - host_permissions zamiast embedowanych w permissions --- ## 🧠 Pamięć i Stan (NAJWIĘKSZA ZMIANA) ### memory.ts - Kompletna refaktoryzacja **Problem Chrome MV3:** - Service worker może być wyładowany w dowolnym momencie - Brak dostępu do window.memory z popup/sidebar - chrome.extension.getBackgroundPage() zwraca null w MV3 **Rozwiązanie:** 1. **Service Worker**: Trzyma pełne dane, synchronizuje do chrome.storage.session 2. **Popup/Sidebar**: Tworzy własną instancję Memory czytając z storage 3. **Throttled sync**: Maksymalnie co 500ms zapisy do storage (wydajność) **Nowa klasa: CachedRequestCluster** - Dziedziczy po RequestCluster ale NIE ma rzeczywistych requestów - Przechowuje tylko metadane: hasCookies, exposesOrigin, hasMarks - Implementuje wszystkie wymagane metody zwracając cached state - Używana TYLKO w popup/report window w Chrome **Zmiany w Memory klasie:** - **Dodano**: isReady flag i readyPromise dla async inicjalizacji (Chrome) - **Dodano**: waitUntilReady() - popup musi poczekać na załadowanie danych - **Dodano**: tabUrls: Map<number, string> - tracking pełnych URL dla Chrome (service worker nie dostaje documentUrl) - **Dodano**: scheduleSyncToStorage() - throttled sync do storage - **Dodano**: syncToStorage() - serializacja clustrów do JSON - **Dodano**: loadFromStorage() - deserializacja przy starcie popup - **Zmieniono**: register() śledzi main_frame URL i synuje po każdej zmianie - **Zmieniono**: Badge operacje w try-catch (karta może być zamknięta) **Funkcja getMemory():** - **Firefox**: browserAPI.extension.getBackgroundPage().memory (tradycyjnie) - **Chrome Service Worker**: self.memory (jesteśmy W service workerze) - **Chrome Popup**: Tworzy NOWĄ instancję czytając z storage (cachowana jako popupMemoryInstance) --- ## 🔒 Bezpieczeństwo i Obsługa Błędów ### util.ts - getshorthost() - **Dodano**: Walidacja wejścia (null, undefined, pusty string) - **Dodano**: Czyszczenie URL (protokół, ścieżka, port) - **Dodano**: Obsługa edge cases (localhost, single word domains) - **Dodano**: Bezpieczne fallbacki zamiast crashowania - **Dodano**: Console.warn zamiast milczących błędów ### extended-request.ts - **MASYWNE POPRAWKI** parsowania URL w konstruktorze - **Dodano**: isValidHttpUrl() helper - sprawdza czy URL zaczyna się od http(s) - **Dodano**: safeParseUrl() helper - try-catch wokół new URL() - **Dodano**: Próba parsowania wielu URL w kolejności priorytetów - **Dodano**: Obsługa Chrome MV3 initiator property - **Dodano**: Bezpieczne defaulty gdy parsowanie się nie uda (unknown://unknown) - **Zmieniono**: isThirdParty() pomija requesty z unparseable URLs - **Dodano**: uint8ArrayToString() - chunked konwersja dużych arrayów (zapobiega stack overflow) - **Zmieniono**: Request body processing używa chunked konwersji --- ## 🎨 UI Components ### toolbar.tsx (popup) - **Dodano**: getCurrentTab() z retry mechanism (Chrome czasem nie zwraca karty od razu) - **Dodano**: Sprawdzanie memoryReady przed renderowaniem danych - **Dodano**: Wywołanie waitUntilReady() w useEffect - **Dodano**: Opóźnienie 200ms dla Chrome przy inicjalizacji (service worker + storage delay) - **Dodano**: Graceful handling gdy popup otwarty bez active tab ### sidebar.tsx - **Dodano**: Stan memoryReady i loading screen dla Chrome - **Dodano**: Wywołanie waitUntilReady() przed dostępem do danych - **Dodano**: Conditional rendering - pokazuje "Ładowanie..." gdy pamięć nie gotowa ### report-window.tsx - **Dodano**: Stan memoryReady i loading message - **Dodano**: Wywołanie waitUntilReady() przed generowaniem raportu - **Dodano**: Fallback konstruowania URL z origin gdy brak visited_url - **Zmieniono**: Filtr clustrów używa hasMarks() zamiast getMarkedRequests().length ### stolen-data-cluster.tsx - **Bez znaczących zmian** - działa z abstrakcją RequestCluster --- ## 🐛 Poprawki Bugów ### background.ts - **Dodano**: Diagnostic logging do debugowania inicjalizacji - **Dodano**: Try-catch wokół init() z error logging - **Dodano**: Różne logi dla Firefox vs Chrome ### memory.ts - badge operations - **Dodano**: Try-catch wokół wszystkich operacji badge - Zapobiega crashowaniu gdy użytkownik zamknie kartę podczas operacji ### chrome.ts - badge adapter - **Dodano**: Try-catch w setBadgeText, setTitle, setBadgeBackgroundColor - Chrome rzuca błędy gdy operujemy na zamkniętych kartach --- ## 📝 Workflow Użytkownika (Chrome) 1. **Użytkownik odwiedza stronę** → Service worker rejestruje requesty → Auto-mark podejrzanych → Sync do storage 2. **Użytkownik otwiera popup** → Tworzy Memory → Czyta ze storage → Pokazuje dane z flagami 3. **Użytkownik (od)zaznacza domeny** → Zmienia flagi → Sync do storage 4. **Użytkownik generuje raport** → Otwiera report-window → Czyta ze storage → Filtruje według hasMarks() --- ## ✅ Rezultat - ✅ **Firefox**: Działa jak wcześniej (background page + window.memory) - ✅ **Chrome**: Pełne wsparcie MV3 (service worker + storage.session) - ✅ **Wspólny kod**: 95% kodu jest shared, tylko warstwa dostępu do API różni się - ✅ **Bezpieczeństwo**: Obsługa wszystkich edge cases w parsowaniu URL - ✅ **Wydajność**: Throttled sync do storage (max co 500ms) - ✅ **UX**: Loading states w popup/sidebar dla Chrome - ✅ **Build**: npm run build-addon:firefox lub npm build-addon dla firefox / npm run build:chrome dla chrome
kuba reviewed 2025-10-24 18:01:37 +02:00
@ -26,1 +26,4 @@
}
// Oczekiwanie na gotowość pamięci Chrome
const [memoryReady, setMemoryReady] = React.useState(process.env.TARGET !== 'chrome');
Owner

Jak to działa? Bo w przeglądarce AFAIK nie mamy dostępu do process.env 🤔

Jak to działa? Bo w przeglądarce AFAIK nie mamy dostępu do process.env 🤔
Owner

Aaa już widzę, że to jest dodawane, oki

Aaa już widzę, że to jest dodawane, oki
kuba marked this conversation as resolved
am0 added 1 commit 2025-10-25 13:29:39 +02:00
am0 added 1 commit 2025-10-25 13:54:37 +02:00
This pull request has changes conflicting with the target branch.
  • package.json

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin refactor/build_time_abstraction:refactor/build_time_abstraction
git checkout refactor/build_time_abstraction
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Reference: icd/rentgen#127
No description provided.