Cogover Learning

API reference @cogover/sdk: Outbound HTTP và secret

Trang này thuộc API reference của @cogover/sdk.

Outbound HTTP fetch

function fetch(input: string, init?: CogoverFetchInit): Promise<CogoverFetchResponse>;
 
interface CogoverFetchInit {
  readonly method?: "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE";
  readonly headers?: Readonly<Record<string, string>>;
  readonly body?: string;
  readonly timeoutMs?: number;
  readonly credential?: string;
}
 
interface CogoverFetchHeaders {
  get(name: string): string | null;
  has(name: string): boolean;
  entries(): IterableIterator<[string, string]>;
  [Symbol.iterator](): IterableIterator<[string, string]>;
}
 
interface CogoverFetchResponse {
  readonly ok: boolean;
  readonly status: number;
  readonly statusText: string;
  readonly url: string;
  readonly redirected: false;
  readonly headers: CogoverFetchHeaders;
  readonly bodyUsed: boolean;
  text(): Promise<string>;
  json<T = unknown>(): Promise<T>;
}

Cogover cài đặt global fetch() trong hosted runtime. Import { fetch } từ @cogover/sdk khi muốn khai báo dependency tường minh; cách này cũng ngăn Node.js trên máy local âm thầm dùng native fetch không bị giới hạn khi chạy test. Hàm fetch của SDK yêu cầu Cogover runtime và luôn dùng lớp network do Cogover quản lý. input phải là URL HTTPS public tuyệt đối, không chứa userinfo, fragment hoặc IP literal, trên port 443 hoặc trên origin đã được duyệt cho project (xem Port khác). body chỉ nhận string; dùng JSON.stringify() cho JSON. timeoutMs phải là số nguyên dương và luôn bị giới hạn bởi hạn mức của platform. Giá trị này không kéo dài lần thực thi: HTTP route mặc định có tổng cộng 8 giây, nên ở đó server chậm hơn sẽ kết thúc toàn bộ lần thực thi (xem Giới hạn của một lần thực thi).

import { fetch } from "@cogover/sdk";
 
const response = await fetch("https://api.example.com/v1/orders", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ id: "ORD-1" }),
  timeoutMs: 5_000,
});

CogoverFetchResponse có ok, status, statusText, url, redirected (luôn false), headers, bodyUsed, text() và json<T>(). Body được buffer có giới hạn và chỉ được đọc một lần. headers.get(name), has(name), entries() và iterator không phân biệt hoa/thường.

V1 không tự follow redirect, không lưu/gửi cookie, không streaming request/response, không WebSocket và không nhận signal, credentials, redirect, proxy, dispatcher, agent, DNS resolver hay TLS configuration. Không hỗ trợ URL HTTP, port khác 443 mà project chưa được duyệt, userinfo hoặc IP-literal host. Header framing/hop-by-hop/proxy/forwarding và header request dành riêng cho Cogover bị từ chối. Request/response, header, thời gian, số call, destination và concurrency đều có quota.

  • Request GET hoặc HEAD có body thất bại với FETCH_BLOCKED.
  • Response nén, tức có Content-Encoding khác identity, thất bại với FETCH_BLOCKED.
  • Body của response được giải mã theo UTF-8: byte không hợp lệ theo UTF-8 thành U+FFFD, nên không đọc chính xác được nội dung nhị phân.
  • Host name phân giải ra địa chỉ không phải public thất bại với FETCH_FAILED.
  • Các lời gọi bắt đầu cùng lúc, ví dụ bằng Promise.all, được gửi lần lượt từng lời gọi.
  • Trigger before-change không được gọi fetch: lời gọi ném PermissionDeniedError có details.reason là "TRIGGER_READ_ONLY". Preview version chế độ chỉ đọc chỉ cho phép GET và HEAD không có credential, các lời gọi khác bị từ chối bằng PermissionDeniedError.

Lỗi được ném dưới dạng CogoverApiError với code FETCH_DISABLED, FETCH_BLOCKED, FETCH_REQUEST_TOO_LARGE, FETCH_RESPONSE_TOO_LARGE, FETCH_TIMEOUT hoặc FETCH_FAILED; quota dùng RateLimitError. Một lần thực thi gọi fetch tối đa 20 lần, và mỗi lần cũng tính vào ngân sách capability call của lần thực thi (xem Giới hạn của một lần thực thi); vượt một trong hai đều được báo bằng RateLimitError. Với POST/PUT/PATCH/DELETE bị timeout hoặc mất response, remote server có thể đã xử lý request. Hãy dùng idempotency key của API đích và không retry mù.

Port khác

Hệ thống chỉ công bố trên port khác, ví dụ https://erp.example.com:9899, gọi được sau khi quản trị viên Workspace duyệt đúng origin đó trong mục fetch của identity policy của project. Việc duyệt chỉ áp dụng cho các origin https://host:port được liệt kê; port khác của cùng host vẫn bị chặn. Mọi quy tắc khác trong mục này vẫn áp dụng cho origin đã duyệt: HTTPS với chứng chỉ hợp lệ cho host, chỉ địa chỉ public, không follow redirect và cùng các giới hạn. URL trên port chưa được duyệt thất bại với FETCH_BLOCKED. Request rời Cogover từ các địa chỉ outbound dùng chung với Workspace khác, nên whitelist các địa chỉ đó trên firewall không xác định được Workspace của bạn: hệ thống đích cần xác thực request, ví dụ bằng credential.

// Chỉ gọi được sau khi "https://erp.example.com:9899" được duyệt cho project này.
const orders = await fetch("https://erp.example.com:9899/api/orders?status=new");

Xác thực bằng credential

credential là tên một credential mà quản trị viên đã lưu cho project (xem Secret và credential). Cogover thêm header xác thực của credential vào request, nên code của project không bao giờ chạm tới giá trị:

const response = await fetch("https://erp.example.com/v1/orders", {
  method: "POST",
  credential: "erp_api",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ id: "ORD-1" }),
});

Tuỳ cách credential được tạo, Cogover gửi Authorization: Bearer <value>, Authorization: Basic <base64 của value> hoặc một header với tên đã cấu hình. Tên phải bắt đầu bằng chữ cái và chứa tối đa 64 chữ cái, chữ số hoặc dấu gạch dưới. Credential chỉ được gửi tới các host mà quản trị viên cho phép. Host ghi không kèm port chỉ cho phép port 443; để dùng credential với origin đã duyệt trên port khác, quản trị viên ghi host:port, ví dụ erp.example.com:9899. Request tới host hoặc port khác, request tự đặt cùng header, hoặc tên không phải credential đang active sẽ thất bại với FETCH_BLOCKED. Redirect không bao giờ được follow, nên credential không bao giờ rời khỏi host được phép.

Secret và credential

Quản trị viên lưu secret cho project qua management API của Cogover. Mỗi secret hoặc là secret có giá trị được code đọc bằng secrets.get, hoặc là credential chỉ dùng cho fetch (xem Xác thực bằng credential); giá trị của credential không bao giờ đọc được từ code. Giá trị được lưu mã hoá và không bao giờ được management API trả về, ghi log hay đưa vào thông báo lỗi.

interface SecretsApi {
  get(name: string): Promise<string>;
}
const token = await secrets.get("erp_token");
const response = await fetch("https://erp.example.com/v1/orders", {
  headers: { authorization: `Bearer ${token}` },
});

secrets.get(name): Promise<string>

Trả về giá trị hiện tại của secret. name bắt đầu bằng chữ cái và chứa tối đa 64 chữ cái, chữ số hoặc dấu gạch dưới; tên khác ném ValidationError trước khi gọi. Secret không tồn tại hoặc đã bị disable ném ValidationError với thông báo Secret '<name>' is not available, còn credential ném ValidationError với Secret '<name>' is a credential and cannot be read.

secrets.get hoạt động trong script và route, trigger after-change, job và lời gọi inbound webhook. Trigger before-change bị từ chối bằng PermissionDeniedError (details.reason === "TRIGGER_READ_ONLY"); phiên phát triển local chỉ đọc được secret khi quản trị viên cho phép, nếu không reason là "SECRETS_NOT_ALLOWED". Một invocation đọc secret tối đa 20 lần; mọi lần đọc đều được tính, kể cả đọc lại cùng tên và thao tác crypto dùng key { secret: name }, và lần thứ 21 ném RateLimitError. secrets.get cũng tính là một capability call, còn thao tác crypto tính là một lời gọi cục bộ (xem Giới hạn của một lần thực thi). Khi secret chưa được bật cho Workspace, lỗi là CogoverApiError với code: "SECRETS_DISABLED". Không bao giờ ghi giá trị secret vào log, record, state hay response. Để ký, mã hoá hoặc giải mã bằng secret mà không đọc giá trị, truyền { secret: name } làm key của một thao tác crypto.

© 2026 Cogover LLC