# Content Scripts

## Tong quan

Content Scripts la thanh phan duoc **inject truc tiep vao cac trang web** thuong mai dien tu (Shopee, Lazada, TikTok, Tiki). Chung chay trong context cua trang web, co the truy cap DOM nhung bi cach ly ve JavaScript scope voi trang goc.

Content Scripts chiu trach nhiem:
- Thu thap du lieu tu DOM va API cua trang web
- Chen cac nut bam, giao dien bo sung (UI injection) vao trang
- Giao tiep voi Background Service Worker qua **webext-bridge**
- Duy tri ket noi voi Background qua **keep-alive ping**
- Intercept va chuyen tiep cac request fetch cua trang web

## Cau truc thu muc

```
src/content/
├── all/                          # Global scripts - chay tren moi trang
│   ├── ping.js                   # Keep-alive cho Service Worker
│   └── listener.js               # Lang nghe su kien tu Background
│
├── service/                      # Utilities dung chung cho tat ca content scripts
│   ├── event.js                  # Fetch listener, load script injection
│   ├── get.js                    # Lay cai dat tu Background
│   ├── util.js                   # DOM utilities (setNativeValue, appendStyle, ...)
│   └── vue.js                    # Tao Vue app trong content script
│
├── file/                         # Xu ly file
│   └── pdf.js                    # Xu ly PDF
│
├── shopee/
│   ├── script/
│   │   └── fetch.js              # Inject vao page context de intercept fetch
│   ├── client/                   # Trang mua hang (shopee.vn)
│   │   ├── loader.js             # Entry point cho client
│   │   ├── shop.js               # Lay thong tin shop/seller
│   │   ├── worker.js             # Worker fetch URL qua Socket.io
│   │   ├── service.js            # Affiliate iframe, image downloader, table style
│   │   └── product/
│   │       ├── detail.js         # Spy san pham chi tiet
│   │       └── search.js         # Spy san pham tren trang tim kiem
│   └── seller/                   # Trang ban hang (banhang.shopee.vn)
│       ├── loader.js             # Entry point cho seller
│       ├── print.js              # In don hang (awbprint)
│       ├── service/
│       │   ├── append.js         # Chen nut bam vao cac trang seller
│       │   └── style.js          # CSS cho cua so chat
│       ├── order/
│       │   └── index.js          # Quan ly don hang
│       ├── marketing/
│       │   ├── index.js          # Entry marketing/flash sale
│       │   └── service.js        # Logic chen nut, mass apply gia
│       ├── chat/
│       │   └── index.js          # Chat tu dong, affiliate link
│       ├── ads/
│       │   ├── index.js          # Entry quang cao
│       │   ├── campaign.js       # Nut mo campaign ID
│       │   └── home.js           # Trang chinh ads (chua implement)
│       └── product/
│           ├── index.js          # Mount Vue component GPT AI
│           ├── utils.js          # Doc/ghi mo ta san pham tu DOM
│           └── GptContent.vue    # Component tao mo ta bang AI
│
├── tiktok/
│   └── loader.js                 # Placeholder (chua implement)
│
├── lazada/
│   └── loader.js                 # Affiliate iframe injection
│
└── tiki/
    └── loader.js                 # Affiliate iframe injection
```

## Dang ky Content Scripts

### Dang ky qua WXT Entrypoints

Content scripts duoc dang ky bang file-based entrypoints trong thu muc `entrypoints/`. Moi file `*.content.js` tu dong duoc WXT phat hien va build.

| Entrypoint file | URL Pattern | Mo ta |
|---|---|---|
| `all-ping.content.js` | `<all_urls>` | Service worker keep-alive |
| `all-listener.content.js` | `<all_urls>` | Global event listener |
| `shopee-client.content.js` | `https://shopee.vn/*` | Trang mua hang Shopee |
| `shopee-seller.content.js` | `https://banhang.shopee.vn/*` | Trang ban hang Shopee |
| `shopee-seller-order.content.js` | `https://banhang.shopee.vn/portal/sale/order/*` | Quan ly don hang |
| `shopee-seller-marketing.content.js` | `https://banhang.shopee.vn/portal/marketing*` | Flash sale, khuyen mai |
| `shopee-seller-ads.content.js` | `https://banhang.shopee.vn/portal/marketing/pas*` | Quang cao Shopee Ads |
| `shopee-seller-chat.content.js` | `https://banhang.shopee.vn/webchat/*` | Chat voi khach hang |
| `shopee-seller-product.content.js` | `https://banhang.shopee.vn/portal/product/*` | Quan ly san pham |
| `shopee-seller-print.content.js` | `https://banhang.shopee.vn/awbprint*` | In don hang (`runAt: document_end`) |
| `shopee-fetch.content.js` | `https://shopee.vn/*`, `https://banhang.shopee.vn/*` | Fetch helper (`world: MAIN`) |
| `tiki.content.js` | `https://*.tiki.vn/*` | Affiliate iframe Tiki |
| `lazada.content.js` | `https://*.lazada.*/*` | Affiliate iframe Lazada |
| `tiktok.content.js` | `https://*.tiktok.com/*` | TikTok loader |
| `file-pdf.content.js` | `*://*/*` | PDF.js loader |

### Cau truc entrypoint

Moi content script la wrapper `defineContentScript()` dung dynamic `import()` de load logic goc tu `src/content/`:

```javascript
// entrypoints/shopee-seller-order.content.js
export default defineContentScript({
  matches: ['https://banhang.shopee.vn/portal/sale/order/*'],
  main() {
    import('@content/shopee/seller/order/index.js');
  },
});
```

WXT tu dong generate `content_scripts` trong manifest tu cac file nay. Khong can sua config khi them content script moi — chi can tao file `*.content.js` trong `entrypoints/`.

### Web Accessible Resources

File `shopee/script/fetch.js` duoc dang ky la **web_accessible_resources** de co the inject truc tiep vao page context (khong bi gioi han boi content script sandbox):

```json
{
  "resources": ["js/content/shopee/script/fetch.js"],
  "matches": ["https://shopee.vn/*", "https://banhang.shopee.vn/*"]
}
```

## Vong doi (Lifecycle)

### 1. Injection

```
Nguoi dung mo trang web
    │
    ▼
Browser khop URL voi manifest content_scripts.matches
    │
    ▼
Inject cac file JS tuong ung vao trang
    │
    ├── ping.js + listener.js (moi trang)
    ├── platform loader (theo domain)
    └── feature scripts (theo URL cu the)
```

### 2. Khoi tao (Initialization)

Moi content script co cach khoi tao rieng, nhung deu theo pattern chung:

- **Ngay lap tuc**: Chay logic chinh khi script duoc load
- **`readystatechange`**: Lang nghe su kien DOM ready de chen UI
- **`setTimeout`**: Delay 1-3 giay de doi trang render xong
- **`onChangeTab`**: Lang nghe thay doi tab tu Background de re-inject UI
- **`setInterval`**: Kiem tra dinh ky de chen UI vao cac element render muon (SPA)

Vi du pattern khoi tao dien hinh (tu `shopee/client/loader.js`):

```javascript
// Chay ngay
loaderContent();

// Delay 3s cho SPA render
setTimeout(() => { loaderContent(); }, 3000);

// Re-init khi tab thay doi (SPA navigation)
onChangeTab(() => {
  setTimeout(() => { loaderContent(); }, 1000);
});

// Polling cho cac element render muon
setInterval(() => {
  btnImageDownloader().catch(() => {});
}, 500);
```

### 3. Giao tiep (Communication)

Xem chi tiet tai muc [Luong giao tiep](#luong-giao-tiep-voi-background).

## Global Scripts

### `all/ping.js` - Keep-Alive Service Worker

Giai quyet van de Service Worker bi browser tat sau 30 giay khong hoat dong (han che cua Manifest V3):

```javascript
const serviceWorkerKeepAlive = () => {
  const port = chrome.runtime.connect({ name: 'keepAlive' });
  port.postMessage({ ping: true, from: 'Content Script' });
};

chrome.runtime.sendMessage({ type: 'wakeUp' });  // Danh thuc SW ngay khi inject
serviceWorkerKeepAlive();                          // Ping lan dau
setInterval(serviceWorkerKeepAlive, 5000);         // Ping moi 5 giay
```

**Co che hoat dong:**
- Khi inject, gui message `wakeUp` de dam bao Service Worker dang chay
- Tao persistent connection qua `chrome.runtime.connect` voi ten `keepAlive`
- Gui ping moi 5 giay de duy tri ket noi
- Script nay chay tren **moi trang** (`<all_urls>`) nen bat ky tab nao mo cung giu SW song

### `all/listener.js` - Message Listener

Cung cap 2 chuc nang cho Background goi den bat ky tab nao:

| Event | Chuc nang |
|---|---|
| `EVENT_TAB_GET_WEBCONTENT_HTML` | Tra ve toan bo HTML cua trang (`document.documentElement.outerHTML`) |
| `EVENT_TAB_CREATE_BLOB_URL` | Chuyen base64 thanh Blob URL (dung cho tai file, hinh anh) |

Ho tro 2 kenh giao tiep:
- **webext-bridge** (`onMessage`) - kenh chinh
- **chrome.runtime.onMessage** - fallback tuong thich

## Scripts theo nen tang

### Shopee Seller (`banhang.shopee.vn`)

#### `seller/loader.js` - Entry Point

Chay tren moi trang `banhang.shopee.vn/*`. Thuc hien:
- Chen cac nut bam AutoShopee vao cac trang seller (rating, order, product)
- Khoi tao **fetch listener** de intercept API call cua trang

Su dung `addBtnLoader()` tu `service/append.js` de chen nut theo URL hien tai:

| URL chua | Nut chen | Chuc nang |
|---|---|---|
| `/portal/settings/shop/rating` | "Tu dong tra loi danh gia" | Mo popup auto reply rating |
| `/portal/sale/order` | "Tu dong danh gia don" | Mo popup auto rating order |
| `/portal/product/list` | "Quan ly san pham" | Mo popup product manager (beta) |

#### `seller/marketing/` - Flash Sale & Khuyen mai

**`index.js`**: Khoi tao tren trang marketing, goi `onMarketingPage()` tai nhieu thoi diem (scroll, readystatechange, delay, tab change).

**`service.js`**: Logic chinh:
- **Chen nut "Flash Sale Hang loat"** vao header trang marketing de mo popup AutoShopee
- **Chen nut "Copy %" va "Copy $"** vao moi san pham trong flash sale/discount campaign
- Ho tro **mass apply gia**: Copy gia goc/phan tram tu san pham dau tien cho tat ca san pham con lai
- Su dung `setNativeValue()` de set gia tri input tuong thich voi React (bypass React controlled input)
- Cau hinh CSS selector co the duoc override tu cai dat (`platformShopConfig.shopee.sellerMarketing`)

#### `seller/chat/` - Chat tu dong

Chen nut **Affiliate Link** vao moi san pham trong giao dien chat:
- Polling moi 500ms de phat hien san pham moi trong cua so chat
- Khi click nut, goi `bridgeShopeeGetAffiliateChatMesage()` de lay link affiliate
- Tu dong dien link vao o nhap tin nhan chat

#### `seller/ads/` - Quang cao

**`index.js`**: Entry point (hien tai cac tinh nang bi **disabled** voi `if (false)`).

**`campaign.js`**: Chen nut "Mo campaign" vao trang chi tiet campaign, cho phep mo popup AutoShopee de quan ly ads.

**`home.js`**: Placeholder, chua co logic.

#### `seller/product/` - Quan ly san pham

**`index.js`**: Mount mot **Vue component** (`GptContent.vue`) truc tiep vao DOM cua trang san pham Shopee:
- Doi 2 giay cho trang render
- Tao container div voi `createContainerApp()`
- Mount Vue app voi `createVueApp()` bao gom View Design UI va i18n

**`GptContent.vue`**: Component tao mo ta san pham bang AI:
- Doc mo ta hien tai tu DOM (`getProductDescription()`)
- Goi `gptWriteContent()` API de tao noi dung moi
- Ho tro preview qua lai giua cac phien ban da tao
- Tu dong giu lai hinh anh mo ta goc
- Yeu cau goi VIP (`isPaidPlan`)

**`utils.js`**: Tinh nang doc/ghi DOM:
- `getProductDescription()` - Doc mo ta tu HTML editor hoac textarea
- `setProductDescription()` - Ghi mo ta vao editor/textarea
- `getListImageDescription()` - Lay danh sach URL hinh trong mo ta
- `getProductName()` - Doc ten san pham tu input

#### `seller/print.js` - In don hang

Chay tren trang `banhang.shopee.vn/awbprint*` voi `run_at: document_end`:
- Doc `job_id` va `shop_id` tu URL query string
- Tao **floating button** co dinh o goc duoi phai man hinh
- Click nut se mo popup AutoShopee tai trang printer voi thong tin job

#### `seller/service/style.js` - CSS Chat

Cung cap ham `resizeChatWindow()` de thay doi kich thuoc cua so chat Shopee bang cach inject CSS custom.

### Shopee Client (`shopee.vn`)

#### `client/loader.js` - Entry Point

Entry chinh cho trang mua hang, khoi tao:
- **ProductSearchLoader**: Hien thi thong tin spy tren trang tim kiem
- **ProductDetailLoader**: Hien thi thong tin spy tren trang chi tiet san pham
- Lang nghe event `EVENT_SHOPEE_PRODUCT_SELECT_VARIANT` tu Background de tu dong click chon phien ban
- Inject CSS cho bang thong tin san pham
- Inject affiliate iframe
- Polling nut tai hinh anh moi 500ms
- Khoi tao fetch listener de intercept API call

#### `client/product/detail.js` - Spy Chi tiet San pham

Class `ProductDetailLoader` cung cap:

**Hien thi thong tin san pham:**
- Ten, vi tri shop, tong da ban, so san pham, thoi gian tao
- Gia (min/max/hien tai), truoc va sau giam gia
- So luong ton kho, luot thich, luot danh gia
- Doanh thu uoc tinh (yeu cau VIP)

**Bang phan loai (models):**
- Hien thi tat ca phien ban san pham sap xep theo so luong da ban
- Gom: ten, hinh, gia, gia goc, ton kho, da ban, doanh thu

**Cac nut bam:**
- "Spy nhanh" - Hien thi bang thong tin ngay tai trang
- "Spy chi tiet" - Mo popup AutoShopee (beta mode)
- "Spy shop" - Mo trang spy shop
- "Clone san pham" - Mo popup clone san pham
- "Xem danh gia" - Mo popup xem review

**Click chon phien ban tu dong:**
- Nhan lenh tu Background qua `EVENT_SHOPEE_PRODUCT_SELECT_VARIANT`
- Tu dong click cac nut chon phien ban theo `titer` (vi tri variant)

#### `client/product/search.js` - Spy Tim kiem

Class `ProductSearchLoader` cung cap:

**Thu thap du lieu tim kiem:**
- Goi API `getSearchKeywordProduct()` de lay du lieu san pham tu ket qua tim kiem
- Dem so san pham quang cao (ads), tong ket qua

**Hien thi thong tin tren moi san pham:**
- Ngay tao san pham, thoi gian da tao
- So luong ban trong thang, doanh thu thang
- Tong so da ban, tong doanh thu
- Thuong hieu (NoBrand duoc danh dau rieng)

**Nhan dien san pham cua minh:**
- San pham cua seller dang dang nhap duoc highlight bang vien tim

**Nut Clone nhanh:**
- Hien thi nut "Copy" khi hover vao hinh san pham
- Click de mo popup clone san pham

**Phan tich quang cao (Ads Spy):**
- Hien thi tu khoa quang cao, loai ads (tu dong/tu khoa)
- Hien thi gia bid quang cao (yeu cau VIP Plus)
- Click vao tu khoa de mo trang tim kiem voi tu khoa do

#### `client/service.js` - Dich vu Client

- `affIframe()`: Chen iframe an de tracking affiliate
- `tableProductStyle()`: Inject CSS cho bang thong tin san pham
- `btnImageDownloader()`: Chen nut "Tai hinh" vao moi hinh san pham (ca hinh chinh va hinh mo ta)

#### `client/shop.js` - Thong tin Shop

Lay thong tin seller hien tai (shopId, username, shopName) tu API `/api/v2/user/profile/get/` va export `getShopeeSellerId()` de cac module khac su dung.

#### `client/worker.js` - Worker Fetch

Class `WorkerFetchUrlService` tao mot **worker node** ket noi Socket.io:
- Nhan lenh fetch URL tu server qua socket event
- Thuc hien fetch trong context trang Shopee (co cookie, session)
- Gui ket qua ve server
- Tu dong tat khi phat hien crawler detection
- Hien tai bi **disabled** (`if (false)`)

### Shopee Script (`shopee/script/fetch.js`)

Day la script duoc inject vao **page context** (khong phai content script sandbox) thong qua `web_accessible_resources`:

**Chuc nang:**
- **Intercept fetch**: Ghi de `window.fetch` de bat tat ca API call cua trang Shopee
- Moi response tu URL chua `/api/` duoc clone va gui ve content script qua `PostMessageFetchListener`
- **Proxy fetch**: Nhan yeu cau fetch tu content script qua `PostMessageFetchUrl` va thuc hien trong page context (co day du cookie/session cua trang)

**Ly do can inject vao page context:**
- Content script bi cach ly ve scope, khong truy cap duoc `window.fetch` cua trang goc
- Fetch trong page context tu dong mang theo cookie va CSRF token cua Shopee
- Cho phep extension goi API Shopee nhu nguoi dung that

### Lazada (`lazada/loader.js`)

Chi thuc hien **affiliate iframe injection**:
- Lay URL affiliate tu Background qua `bridgeGetAffiliateUrl('lazada')`
- Chen iframe 0x0 pixel vao body
- Retry sau 5 giay neu lan dau that bai

### Tiki (`tiki/loader.js`)

Tuong tu Lazada, chi thuc hien **affiliate iframe injection** cho nen tang Tiki.

### TikTok (`tiktok/loader.js`)

Hien tai la **placeholder** (chi co comment `// tiktok`), chua implement tinh nang nao.

## Luong giao tiep voi Background

### Kenh giao tiep

```
┌─────────────────┐         webext-bridge          ┌──────────────────┐
│  Content Script  │◄──────────────────────────────►│    Background    │
│                  │                                │  Service Worker  │
│  onMessage()     │   sendMessage() / onMessage()  │                  │
└────────┬────────┘                                └──────────────────┘
         │
         │  PostMessage (window.postMessage)
         ▼
┌─────────────────┐
│  Page Context    │
│  (fetch.js)      │
│                  │
│  Intercept fetch │
│  Proxy API calls │
└─────────────────┘
```

### Cac su kien chinh

| Event | Huong | Mo ta |
|---|---|---|
| `EVENT_TAB_ON_CHANGE` | Background -> Content | Thong bao tab da thay doi (SPA navigation) |
| `EVENT_TAB_FETCH_URL` | Background -> Content | Yeu cau content script fetch URL trong page context |
| `EVENT_TAB_GET_WEBCONTENT_HTML` | Background -> Content | Lay toan bo HTML cua trang |
| `EVENT_TAB_CREATE_BLOB_URL` | Background -> Content | Tao Blob URL tu base64 |
| `EVENT_SHOPEE_PRODUCT_SELECT_VARIANT` | Background -> Content | Tu dong click chon phien ban san pham |

### Bridge functions (Content -> Background)

Content scripts su dung cac ham `bridge*` tu `@/bridge/content/background` de giao tiep:

| Ham | Chuc nang |
|---|---|
| `bridgeOpenPopupUrl({ path, qs })` | Mo popup/options page tai duong dan chi dinh |
| `bridgeGetSetting(key)` | Lay cai dat tu Background |
| `bridgeGetUserInfo()` | Lay thong tin user (isPaidPlan, isVipPlus) |
| `bridgeShopeeSaveProductId(data)` | Luu du lieu san pham vao PouchDB |
| `bridgeGetAffiliateUrl(platform)` | Lay URL affiliate theo nen tang |
| `bridgeShopeeGetAffiliateChatMesage(data)` | Lay tin nhan affiliate cho chat |
| `bridgeShopeeListenFetch(data)` | Gui du lieu fetch intercepted ve Background |
| `bridgeGetScriptUrl(fileName)` | Lay URL cua web accessible resource |

### PostMessage (Content Script <-> Page Context)

Giao tiep giua content script sandbox va page context thong qua `window.postMessage`:

| Channel | Huong | Chuc nang |
|---|---|---|
| `PostMessageFetchUrl` | Content -> Page | Gui yeu cau fetch, nhan response |
| `PostMessageFetchListener` | Page -> Content | Nhan du lieu fetch intercepted tu page |

## DOM Manipulation Patterns

### 1. Chen nut bam (Button Injection)

Pattern pho bien nhat: tim element co san, tao button moi, chen vao vi tri phu hop.

```javascript
// Pattern: Tim -> Kiem tra trung lap -> Tao -> Chen
const addButton = async () => {
  // Kiem tra element cha ton tai
  if (!document.querySelector(parentSelector)) {
    return false;
  }

  // Kiem tra da chen chua (tranh trung lap)
  if (document.querySelector(`#${buttonId}`)) {
    return false;
  }

  // Tao button
  const button = document.createElement('button');
  button.id = buttonId;
  button.addEventListener('click', handler);

  // Chen vao DOM
  appendNextNode(parentElement, button);
};
```

### 2. Set gia tri input React (`setNativeValue`)

Shopee su dung React, nen khong the gan `input.value` truc tiep. Can mo phong event React:

```javascript
const setNativeValue = (element, value) => {
  const lastValue = element.value;
  element.value = value;

  const event = new Event('input', { target: element, bubbles: true });
  event.simulated = true;

  // Reset React internal tracker de React nhan biet thay doi
  const tracker = element._valueTracker;
  if (tracker) {
    tracker.setValue(lastValue);
  }

  element.dispatchEvent(event);
};
```

### 3. Inject CSS

```javascript
const appendStyle = async (cssText) => {
  const style = document.createElement('style');
  style.innerHTML = cssText;
  document.head.appendChild(style);
};
```

### 4. Mount Vue Component vao DOM

Cho phep chen Vue component phuc tap (co View Design UI, i18n) vao trang web:

```javascript
// Tao container
const container = createContainerApp('vue-app-id');
document.querySelector(parentSelector).prepend(container);

// Mount Vue app
createVueApp(MyComponent).$mount('#vue-app-id');
```

Ham `createVueApp()` tu dong load:
- View Design (iView) CSS tu CDN
- Font Awesome CSS
- App style CSS
- Cau hinh Vue voi ViewUI plugin va VueI18n

### 5. Intercept Fetch API

Inject script vao page context de ghi de `window.fetch`:

```javascript
const { fetch: originalFetch } = window;
window.fetch = async (...args) => {
  const [url, payload] = args;
  const response = await originalFetch(...args);

  // Clone response de doc du lieu ma khong anh huong response goc
  if (url.includes('/api/')) {
    const clone = response.clone();
    clone.json().then((json) => {
      callback({ json, url, payload });
    });
  }

  return response;
};
```

### 6. SPA Navigation Handling

Vi cac trang e-commerce la SPA, content scripts can phat hien navigation ma khong reload trang:

```javascript
// Nhan thong bao tu Background khi URL thay doi
onChangeTab(() => {
  setTimeout(() => {
    reinitialize();
  }, 1000);
});

// Polling cho element chua render
setInterval(() => {
  checkAndInjectUI();
}, 500);

// Lang nghe scroll (trang Shopee load them khi scroll)
window.onscroll = () => {
  reinitialize();
};
```

## Xu ly loi (Error Handling)

Content scripts su dung cac pattern xu ly loi thong nhat:

### 1. Silent catch voi logging

```javascript
someFunction().catch((error) => {
  loggerContent.error({
    msg: 'ERROR_CODE',
    error,
  });
});
```

### 2. Silent catch khong logging

Dung cho cac thao tac khong quan trong (UI injection co the that bai khi DOM chua san sang):

```javascript
onMarketingPage().catch(() => {});
```

### 3. Try-catch trong vong lap

Khi xu ly nhieu element, loi o mot element khong anh huong cac element khac:

```javascript
document.querySelectorAll(selector).forEach((element) => {
  try {
    // Logic xu ly
  } catch (error) {
    loggerContent.error({ msg: 'LOOP_ERROR', error });
  }
});
```

### 4. Kiem tra element truoc khi thao tac

Luon kiem tra element ton tai truoc khi truy cap de tranh `TypeError`:

```javascript
if (!document.querySelector(selector)) {
  return false;
}
```

## Luu y quan trong

### Gioi han cua Content Scripts
- **Cach ly scope**: Content scripts khong truy cap duoc `window` cua trang goc. Can inject script qua `web_accessible_resources` neu muon truy cap
- **SPA**: Cac trang e-commerce la Single Page Application, content scripts chi duoc inject 1 lan khi trang load. Can su dung polling va event listener de phat hien thay doi
- **DOM thay doi**: Element co the bi re-render bat ky luc nao boi React/Vue cua trang goc, can kiem tra va re-inject UI

### Performance
- Polling (`setInterval`) duoc su dung tiet kiem (500ms-5000ms)
- Moi element duoc gan `id` duy nhat de tranh inject trung lap
- Fetch listener chi clone response cho URL chua `/api/`

### Bao mat
- Fetch interceptor chi hoat dong tren domain Shopee (gioi han boi manifest `matches`)
- Worker fetch service co co che phat hien crawler va tu dong ngung
- Tat ca giao tiep voi Background di qua webext-bridge (bao mat boi browser)
