# Cloudflare Workers

> Bọc Worker bằng withBelvador để mỗi lần chạy có phạm vi riêng và lỗi được gửi mà phản hồi không đổi.

`@belvador/cloudflare` bọc một Cloudflare Worker để lỗi trong các handler được báo, còn response giữ đúng như code của bạn trả về. Với ứng dụng TanStack Start hoặc Lovable, dùng [TanStack Start](https://belvador.dev/vi/docs/sdk/tanstack-start) — gói đó đã gồm phần này.

## Trước khi bắt đầu

- Một project và DSN của nó. Danh sách nền tảng chưa có mục Workers; chọn **Khác** — nền tảng chỉ quyết định phần hướng dẫn hiện trong ứng dụng.
- Một Worker viết theo cú pháp ES module (`export default { fetch … }`) và triển khai bằng Wrangler.
- Cờ tương thích **`nodejs_compat`**. Cờ này cho mỗi lần chạy một phạm vi riêng, nên user, tag và ngữ cảnh không bao giờ lẫn giữa các request.

## 1. Cài đặt

```bash
npm install @belvador/cloudflare@0.6.1
```

## 2. Bật `nodejs_compat`

Trong `wrangler.jsonc` (hoặc khoá tương ứng trong `wrangler.toml`):

```jsonc title="wrangler.jsonc"
{
  "compatibility_flags": ["nodejs_compat"]
}
```

## 3. Bọc Worker

```ts title="src/index.ts"
import { withBelvador } from "@belvador/cloudflare";

type Env = { BELVADOR_DSN?: string; BELVADOR_RELEASE?: string };

// Requires the nodejs_compat compatibility flag.
// The DSN comes from env.BELVADOR_DSN when you leave it out here.
export default withBelvador(
  (env: Env) => ({
    dsn: env.BELVADOR_DSN ?? "https://<public-key>@ingest.belvador.dev/<project-id>",
    release: env.BELVADOR_RELEASE,
  }),
  {
    async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
      return new Response("ok");
    },
  },
);
```

Nếu muốn để DSN ngoài code — đặt DSN làm secret của Worker và SDK sẽ tự đọc:

```bash
npx wrangler secret put BELVADOR_DSN
```

| Biến | Dùng cho | Mặc định |
|---|---|---|
| `BELVADOR_DSN` | DSN của project, khi callback cấu hình không trả về `dsn` | — (SDK tắt) |
| `BELVADOR_RELEASE` | Phiên bản của lần triển khai | `CF_VERSION_METADATA.id` nếu có binding đó |
| `BELVADOR_ENVIRONMENT` | `production`, `staging`, … | `production` |
| `BELVADOR_DISABLED` | `1` hoặc `true` để tắt việc gửi | — |

SDK không bao giờ đọc biến `SENTRY_*`.

## Những gì được báo

`withBelvador` bọc các handler trên object được export: `fetch`, `scheduled`, `queue`, `email` và `tail`.

- Mỗi lần chạy có phạm vi riêng.
- Lỗi do handler ném ra được báo, rồi **ném lại** — Cloudflare thấy đúng lỗi như khi không có Belvador.
- Response của bạn (mã trạng thái, header, body dạng stream) được trả về không đổi.
- Request bị huỷ không được báo (từ 0.2.0): một `AbortError`, hoặc lỗi ném ra sau khi client đã ngắt kết nối. Đặt [`captureAborted: true`](https://belvador.dev/vi/docs/sdk/configuration#tuy-chon-chung) nếu vẫn muốn báo.
- Promise bạn đưa vào `ctx.waitUntil` mà bị reject sẽ được báo thành lỗi không được xử lý, mang scope của request (từ 0.4.1), rồi vẫn được giao nguyên cho Cloudflare nên Workers Logs vẫn thấy. Lỗi phải xảy ra trong khoảng 2 giây sau khi handler trả về, lúc SDK còn đang gửi; lỗi muộn hơn, hoặc promise không đưa vào `waitUntil`, sẽ không được thấy.
- Việc gửi hoàn tất sau khi trả response, trong `ctx.waitUntil`, nên không làm người dùng phải chờ.

Các điểm vào khác, như class Durable Object, chưa được bọc trong bản 0.x.

## Báo những lỗi bạn đã xử lý

```ts
import { captureException, setTag, withBelvador } from "@belvador/cloudflare";

export default withBelvador(() => ({}), {
  async fetch(request: Request): Promise<Response> {
    setTag("route", new URL(request.url).pathname);
    try {
      return await handle(request);
    } catch (error) {
      captureException(error);
      return new Response("Something went wrong", { status: 502 });
    }
  },
});
```

Tag ở trên chỉ giữ đường dẫn; SDK cũng che các thông tin đăng nhập mà nó nhận ra trong URL và query string.

## Breadcrumb

Breadcrumb từ console và `fetch` mặc định tắt. Bật trong callback cấu hình:

```ts
withBelvador((env: { BELVADOR_RELEASE?: string }) => ({
  release: env.BELVADOR_RELEASE,
  instrument: { console: true, fetch: true },
}), worker);
```

## Kiểm tra

Triển khai một phép kiểm tạm trong handler được bọc bằng `withBelvador`, gọi một lần rồi đọc lại kết quả (hoặc mở tab **Kết nối** của project):

```ts title="src/index.ts"
import { verifyIntegration } from "@belvador/cloudflare";

// Inside the fetch handler wrapped by withBelvador. Temporary: remove after the check.
if (new URL(request.url).pathname === "/__belvador/verify") {
  return Response.json(await verifyIntegration());
}
```

```bash
curl -s "https://ingest.belvador.dev/api/<project-id>/verification/bv1_<id printed by your app>/?sentry_key=<public-key>"
```

Xoá phép kiểm sau đó — xem [Kiểm tra kết nối](https://belvador.dev/vi/docs/sdk/verify).
