# Debug: "Receiving end does not exist" Error Spam

## Triệu chứng

Console của service worker background log hàng nghìn lần:

```
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
```

Lỗi xuất hiện liên tục từ context `[background]` (service worker).

## Nguyên nhân gốc rễ

**Commit gây ra:** `4bc84543` (entrypoin)

**File gây ra:** `node_modules/webext-bridge/dist/chunk-E2HJRHOS.js`

### Cơ chế hoạt động của webext-bridge

webext-bridge dùng **persistent port** (`chrome.runtime.connect`) để duy trì kết nối giữa content script và background service worker.

```
Content Script ──connect()──► Background SW (port)
                ◄─────────────
```

Khi service worker trong MV3 **sleep** (bị Chrome tắt sau ~30 giây idle):
1. Port bị ngắt kết nối → `port.onDisconnect` fire
2. webext-bridge **reconnect ngay lập tức** (`port.onDisconnect.addListener(connect)`)
3. SW chưa wake kịp → `port.postMessage` hoặc `connect()` fail
4. Lại disconnect → lại reconnect → **vòng lặp vô tận**
5. Chrome không thể log `lastError` vì `onDisconnect` listener không đọc `chrome.runtime.lastError`

### Tại sao spam?

Mỗi content script inject webext-bridge tạo 1 persistent port. Extension có nhiều content scripts chạy trên nhiều tab (all-listener, shopee-client, shopee-seller, v.v.) → tất cả đều loop cùng lúc → hàng nghìn lỗi/giây.

## Fix

**File:** `node_modules/webext-bridge/dist/chunk-E2HJRHOS.js`

### 1. Đọc `chrome.runtime.lastError` trong `onDisconnect`

Chrome yêu cầu phải đọc `lastError` trong callback, nếu không sẽ log "Unchecked":

```js
// TRƯỚC (gây lỗi)
port.onDisconnect.addListener(connect);

// SAU (fix)
port.onDisconnect.addListener(() => {
  void chrome.runtime.lastError;  // suppress "Unchecked" log
  // reconnect...
});
```

### 2. Thêm delay khi reconnect

Tránh vòng lặp reconnect liên tục khi SW chưa ready:

```js
// TRƯỚC (loop ngay lập tức)
port.onDisconnect.addListener(connect);

// SAU (delay 1 giây)
port.onDisconnect.addListener(() => {
  void chrome.runtime.lastError;
  setTimeout(connect, 1000);
});
```

### 3. try/catch cho `port.postMessage`

```js
postMessage(message) {
  try {
    PortMessage.toBackground(port, { type: "deliver", message });
  } catch (e) {}
}
```

## Code fix hoàn chỉnh

Trong `node_modules/webext-bridge/dist/chunk-E2HJRHOS.js`, thay hàm `createPersistentPort`:

```js
const connect = () => {
  let reconnectTimer = null;
  try {
    port = browser.runtime.connect({
      name: encodeConnectionArgs({ endpointName: name, fingerprint })
    });
  } catch (e) {
    reconnectTimer = setTimeout(connect, 1000);
    return;
  }
  port.onMessage.addListener(handleMessage);
  port.onDisconnect.addListener(() => {
    void chrome.runtime.lastError;   // ← bắt buộc để suppress log
    if (reconnectTimer) clearTimeout(reconnectTimer);
    reconnectTimer = setTimeout(connect, 1000);  // ← delay tránh loop
  });
  try {
    PortMessage.toBackground(port, {
      type: "sync",
      pendingResponses: pendingResponses.entries(),
      pendingDeliveries: [...new Set(undeliveredQueue.map(({ resolvedDestination }) => resolvedDestination))]
    });
  } catch (e) {}
};
```

```js
postMessage(message) {
  try {
    PortMessage.toBackground(port, { type: "deliver", message });
  } catch (e) {}
}
```

## Lưu ý quan trọng

- Fix này nằm trong `node_modules` → **sẽ bị mất khi `npm install`**
- Cần dùng `patch-package` để persist fix (xem bên dưới)
- Hoặc upgrade `webext-bridge` lên version mới hơn nếu đã fix upstream

## Persist fix với patch-package

```bash
npm install patch-package --save-dev
npx patch-package webext-bridge
# Tạo ra file patches/webext-bridge+x.x.x.patch
```

Thêm vào `package.json`:
```json
{
  "scripts": {
    "postinstall": "patch-package && wxt prepare"
  }
}
```

## Các fix không hiệu quả (đã thử)

| Fix | Lý do không đủ |
|-----|----------------|
| Filter `changeInfo.status !== 'complete'` trong `tabOnUpdate` | Giảm số lần gửi nhưng không fix loop |
| Reuse port trong `all-ping.content.js` | Không liên quan đến webext-bridge port |
| Chuyển `bridgeTabOnChange` sang `chrome.tabs.sendMessage` | Fix 1 message nhưng không fix loop |
| Xóa `browserSendMessage` trong `event.js` | Fix dead code nhưng không phải nguồn chính |

**Nguồn thực sự là webext-bridge reconnect loop** — chỉ fix khi thêm `void chrome.runtime.lastError` và `setTimeout(connect, 1000)`.
