quality / changes (push) Successful in 9s
quality / commitlint (push) Skipped
quality / docker-check (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / web (push) Successful in 1m4s
quality / api (push) Successful in 54s
CD / quality (push) Successful in 2m17s
CD / publish (push) Successful in 2m21s
Worker сам ходит на origin по Cron Trigger; CFDM кладёт цели в KV и забирает результаты без POST /probe. Co-authored-by: Cursor <[email protected]>
101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
import { CF_API_BASE, handleCfResponse, handleCfSuccess, mapCloudflareFailure } from "./http.js";
|
|
|
|
export interface CfKvNamespace {
|
|
id: string;
|
|
title: string;
|
|
}
|
|
|
|
export function createKvAdapter(token: string) {
|
|
return {
|
|
async listNamespaces(accountId: string): Promise<CfKvNamespace[]> {
|
|
const all: CfKvNamespace[] = [];
|
|
let page = 1;
|
|
while (true) {
|
|
const url = new URL(
|
|
`${CF_API_BASE}/accounts/${accountId}/storage/kv/namespaces`,
|
|
);
|
|
url.searchParams.set("per_page", "100");
|
|
url.searchParams.set("page", String(page));
|
|
const response = await fetch(url.toString(), {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
signal: AbortSignal.timeout(30_000),
|
|
});
|
|
if (response.status >= 500 || response.status === 429) {
|
|
throw mapCloudflareFailure("kv_list", response.status, String(response.status));
|
|
}
|
|
const batch = await handleCfResponse<CfKvNamespace[]>(response, "kv_list");
|
|
all.push(...batch);
|
|
if (batch.length < 100) break;
|
|
page += 1;
|
|
}
|
|
return all;
|
|
},
|
|
|
|
async createNamespace(accountId: string, title: string): Promise<CfKvNamespace> {
|
|
const response = await fetch(
|
|
`${CF_API_BASE}/accounts/${accountId}/storage/kv/namespaces`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({ title }),
|
|
signal: AbortSignal.timeout(30_000),
|
|
},
|
|
);
|
|
if (response.status >= 500 || response.status === 429) {
|
|
throw mapCloudflareFailure("kv_create", response.status, String(response.status));
|
|
}
|
|
return handleCfResponse<CfKvNamespace>(response, "kv_create");
|
|
},
|
|
|
|
async getValue(
|
|
accountId: string,
|
|
namespaceId: string,
|
|
key: string,
|
|
): Promise<string | null> {
|
|
const response = await fetch(
|
|
`${CF_API_BASE}/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(key)}`,
|
|
{
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
signal: AbortSignal.timeout(30_000),
|
|
},
|
|
);
|
|
if (response.status === 404) return null;
|
|
if (response.status >= 500 || response.status === 429) {
|
|
throw mapCloudflareFailure("kv_get", response.status, String(response.status));
|
|
}
|
|
if (!response.ok) {
|
|
const text = await response.text().catch(() => "");
|
|
throw mapCloudflareFailure("kv_get", response.status, text.slice(0, 180));
|
|
}
|
|
return response.text();
|
|
},
|
|
|
|
async putValue(
|
|
accountId: string,
|
|
namespaceId: string,
|
|
key: string,
|
|
value: string,
|
|
): Promise<void> {
|
|
const response = await fetch(
|
|
`${CF_API_BASE}/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/values/${encodeURIComponent(key)}`,
|
|
{
|
|
method: "PUT",
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "text/plain",
|
|
},
|
|
body: value,
|
|
signal: AbortSignal.timeout(30_000),
|
|
},
|
|
);
|
|
if (response.status >= 500 || response.status === 429) {
|
|
throw mapCloudflareFailure("kv_put", response.status, String(response.status));
|
|
}
|
|
await handleCfSuccess(response, "kv_put");
|
|
},
|
|
};
|
|
}
|