@dragonmastery/tamer 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{apply-CWU3HY0P.mjs → apply-BjrYbyHn.mjs} +14 -16
- package/dist/{apply-CWU3HY0P.mjs.map → apply-BjrYbyHn.mjs.map} +1 -1
- package/dist/{applyTarget-D15T_q7G.mjs → applyTarget-Ce_mtRQX.mjs} +3 -3
- package/dist/{applyTarget-D15T_q7G.mjs.map → applyTarget-Ce_mtRQX.mjs.map} +1 -1
- package/dist/{bootstrap-BicPW44a.mjs → bootstrap-D__dHw1w.mjs} +6 -6
- package/dist/bootstrap-D__dHw1w.mjs.map +1 -0
- package/dist/{buildDispatchUploadForm-BoUB93b3.mjs → buildDispatchUploadForm-CVnPmHg4.mjs} +1 -1
- package/dist/{buildDispatchUploadForm-BoUB93b3.mjs.map → buildDispatchUploadForm-CVnPmHg4.mjs.map} +1 -1
- package/dist/{cloudflareSnapshot-GBUHeg2m.mjs → cloudflareSnapshot-C6cF8GG8.mjs} +5 -7
- package/dist/{cloudflareSnapshot-GBUHeg2m.mjs.map → cloudflareSnapshot-C6cF8GG8.mjs.map} +1 -1
- package/dist/{deploy-DAEjDjOm.mjs → deploy-C6fX9td0.mjs} +23 -11
- package/dist/deploy-C6fX9td0.mjs.map +1 -0
- package/dist/{destroy-tenant-B-VLKfc6.mjs → destroy-tenant-T_94ed9x.mjs} +2 -4
- package/dist/{destroy-tenant-B-VLKfc6.mjs.map → destroy-tenant-T_94ed9x.mjs.map} +1 -1
- package/dist/{destroy-DtgPD_bD.mjs → destroy-vfk2Zbfj.mjs} +11 -13
- package/dist/{destroy-DtgPD_bD.mjs.map → destroy-vfk2Zbfj.mjs.map} +1 -1
- package/dist/{dev-BYItpt9U.mjs → dev-BLthyLml.mjs} +8 -10
- package/dist/{dev-BYItpt9U.mjs.map → dev-BLthyLml.mjs.map} +1 -1
- package/dist/{dns-records.resolve-C2T0m4NG.mjs → dns-records.resolve-8a_eHfVI.mjs} +1 -1
- package/dist/{dns-records.resolve-DwBR_1WI.mjs → dns-records.resolve-BB2agPAb.mjs} +1 -1
- package/dist/{dns-records.resolve-DwBR_1WI.mjs.map → dns-records.resolve-BB2agPAb.mjs.map} +1 -1
- package/dist/{dns-records.sync-CfI1mqXv.mjs → dns-records.sync-DqYROe07.mjs} +3 -3
- package/dist/{dns-records.sync-CfI1mqXv.mjs.map → dns-records.sync-DqYROe07.mjs.map} +1 -1
- package/dist/{doctor-C_hs7k2D.mjs → doctor-32YLAXXl.mjs} +2 -2
- package/dist/{doctor-C_hs7k2D.mjs.map → doctor-32YLAXXl.mjs.map} +1 -1
- package/dist/drift-BCxWdYHG.mjs +8 -0
- package/dist/{drift-DncpkI2R.mjs → drift-CeemyFqL.mjs} +37 -9
- package/dist/drift-CeemyFqL.mjs.map +1 -0
- package/dist/{events-B6oCdvSt.mjs → events-otk0l3aJ.mjs} +2 -4
- package/dist/{events-B6oCdvSt.mjs.map → events-otk0l3aJ.mjs.map} +1 -1
- package/dist/{generator-h_VG0Q5f.mjs → generator-gvCy7ouY.mjs} +2 -2
- package/dist/{generator-h_VG0Q5f.mjs.map → generator-gvCy7ouY.mjs.map} +1 -1
- package/dist/{import-D8zaVvwK.mjs → import-OvohE-H2.mjs} +6 -8
- package/dist/{import-D8zaVvwK.mjs.map → import-OvohE-H2.mjs.map} +1 -1
- package/dist/index.d.mts +264 -26
- package/dist/index.d.mts.map +1 -1
- package/dist/{logpush-job-DsRkOORJ.mjs → logpush-job-DJPlpnRu.mjs} +2 -2
- package/dist/{logpush-job-DsRkOORJ.mjs.map → logpush-job-DJPlpnRu.mjs.map} +1 -1
- package/dist/{migrate-Bwl0w6XN.mjs → migrate-CroDjbJz.mjs} +6 -8
- package/dist/{migrate-Bwl0w6XN.mjs.map → migrate-CroDjbJz.mjs.map} +1 -1
- package/dist/normalize-DVSTRZhO.mjs.map +1 -1
- package/dist/{plan-BNIAD--f.mjs → plan-C2urqJOz.mjs} +39 -14
- package/dist/plan-C2urqJOz.mjs.map +1 -0
- package/dist/{planFormat-CJw8Kq2s.mjs → planFormat-5XMJK879.mjs} +1 -1
- package/dist/{planFormat-CJw8Kq2s.mjs.map → planFormat-5XMJK879.mjs.map} +1 -1
- package/dist/{provision-tenant-BcZocyyn.mjs → provision-tenant-BJ1KugON.mjs} +6 -8
- package/dist/{provision-tenant-BcZocyyn.mjs.map → provision-tenant-BJ1KugON.mjs.map} +1 -1
- package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs → r2S3EmptyBucket-B9_pHfvB.mjs} +1 -1
- package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs.map → r2S3EmptyBucket-B9_pHfvB.mjs.map} +1 -1
- package/dist/{fetchStackImports-ClUYZy_U.mjs → registry-EWWdkLf7.mjs} +5 -982
- package/dist/registry-EWWdkLf7.mjs.map +1 -0
- package/dist/secrets-CnzjvndT.mjs +3 -0
- package/dist/{stackOutputs-D33EmyfT.mjs → stackOutputs-Cltzl2g0.mjs} +2 -2
- package/dist/{stackOutputs-D33EmyfT.mjs.map → stackOutputs-Cltzl2g0.mjs.map} +1 -1
- package/dist/{status-BAPpi2Zt.mjs → status-DkkS5lc9.mjs} +7 -9
- package/dist/{status-BAPpi2Zt.mjs.map → status-DkkS5lc9.mjs.map} +1 -1
- package/dist/{sync-BdJ43vO7.mjs → sync-CpfxqlOx.mjs} +7 -9
- package/dist/{sync-BdJ43vO7.mjs.map → sync-CpfxqlOx.mjs.map} +1 -1
- package/dist/tamer.mjs +4423 -221
- package/dist/tamer.mjs.map +1 -1
- package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs → tamerArtifactsR2-DnUJmxnO.mjs} +2 -2
- package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs.map → tamerArtifactsR2-DnUJmxnO.mjs.map} +1 -1
- package/dist/{types-CN1BOr0U.mjs → types-BzzHwIdw.mjs} +6 -8
- package/dist/{types-CN1BOr0U.mjs.map → types-BzzHwIdw.mjs.map} +1 -1
- package/dist/{verifyPlanFile-BQ7GCDC2.mjs → verifyPlanFile-BmEadIqm.mjs} +2 -2
- package/dist/{verifyPlanFile-BQ7GCDC2.mjs.map → verifyPlanFile-BmEadIqm.mjs.map} +1 -1
- package/dist/{wfp-delete-BG9WBd7F.mjs → wfp-delete-CDBFqmrM.mjs} +2 -3
- package/dist/{wfp-delete-BG9WBd7F.mjs.map → wfp-delete-CDBFqmrM.mjs.map} +1 -1
- package/dist/{wfp-put-DjErqxFa.mjs → wfp-put-BrwICc9i.mjs} +3 -4
- package/dist/{wfp-put-DjErqxFa.mjs.map → wfp-put-BrwICc9i.mjs.map} +1 -1
- package/dist/{worker-route-DY1onr-h.mjs → worker-route-x8q3K4-z.mjs} +3 -4
- package/dist/{worker-route-DY1onr-h.mjs.map → worker-route-x8q3K4-z.mjs.map} +1 -1
- package/dist/{workers-DNKsZOq4.mjs → workers-D3Ekf3mF.mjs} +3 -4
- package/dist/{workers-DNKsZOq4.mjs.map → workers-D3Ekf3mF.mjs.map} +1 -1
- package/dist/{wranglerSpawn-DmEz0ldT.mjs → wranglerSpawn-CUlo2qOJ.mjs} +1 -1
- package/dist/{wranglerSpawn-DmEz0ldT.mjs.map → wranglerSpawn-CUlo2qOJ.mjs.map} +1 -1
- package/dist/{zoneResolver-VoxLHM4N.mjs → zoneResolver-DNNNmO_w.mjs} +1 -1
- package/dist/{zoneResolver-VoxLHM4N.mjs.map → zoneResolver-DNNNmO_w.mjs.map} +1 -1
- package/package.json +1 -1
- package/dist/CFApiClient-DhbyyV71.mjs +0 -868
- package/dist/CFApiClient-DhbyyV71.mjs.map +0 -1
- package/dist/StateManager-JLBtz9V-.mjs +0 -760
- package/dist/StateManager-JLBtz9V-.mjs.map +0 -1
- package/dist/bootstrap-BicPW44a.mjs.map +0 -1
- package/dist/deploy-DAEjDjOm.mjs.map +0 -1
- package/dist/drift-DRnwTyZD.mjs +0 -10
- package/dist/drift-DncpkI2R.mjs.map +0 -1
- package/dist/fetchStackImports-ClUYZy_U.mjs.map +0 -1
- package/dist/loader-DnT9iqz9.mjs +0 -531
- package/dist/loader-DnT9iqz9.mjs.map +0 -1
- package/dist/plan-BNIAD--f.mjs.map +0 -1
|
@@ -1,868 +0,0 @@
|
|
|
1
|
-
//#region src/core/cloudflareEnv.ts
|
|
2
|
-
/**
|
|
3
|
-
* Wrangler-aligned Cloudflare credentials (same names as `wrangler` CLI).
|
|
4
|
-
* @see https://developers.cloudflare.com/workers/wrangler/system-environment-variables/
|
|
5
|
-
*/
|
|
6
|
-
function cloudflareAccountIdFromEnv() {
|
|
7
|
-
return process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
8
|
-
}
|
|
9
|
-
function cloudflareApiTokenFromEnv() {
|
|
10
|
-
return process.env.CLOUDFLARE_API_TOKEN ?? "";
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/core/api/pipelinesV1PathId.ts
|
|
15
|
-
/**
|
|
16
|
-
* Pipelines v1 path segments (streams, sinks, SQL pipelines) expect **stream_id**
|
|
17
|
-
* / **sink_id** as **exactly 32 lower-case hex characters** (no hyphens). The API
|
|
18
|
-
* returns 400 if the URL contains a hyphenated UUID (36 chars) — see
|
|
19
|
-
* `stream_id: String must contain exactly 32 character(s)`.
|
|
20
|
-
*
|
|
21
|
-
* State and list APIs may return ids with or without hyphens; we normalize to 32-hex
|
|
22
|
-
* for GET/DELETE paths.
|
|
23
|
-
*/
|
|
24
|
-
function pipelinesV1IdForPath(id) {
|
|
25
|
-
const c = id.trim().toLowerCase().replace(/-/g, "");
|
|
26
|
-
if (!/^[0-9a-f]{32}$/.test(c)) return id.trim();
|
|
27
|
-
return c;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/core/api/CFApiClient.ts
|
|
32
|
-
const CF_API_BASE = "https://api.cloudflare.com/client/v4";
|
|
33
|
-
/**
|
|
34
|
-
* Renders the Cloudflare API `errors` / `messages` array into a single string
|
|
35
|
-
* (message, error code, documentation URL, JSON pointer) for operator-friendly logs.
|
|
36
|
-
*/
|
|
37
|
-
function describeCloudflareErrorItem(e) {
|
|
38
|
-
if (e == null) return "null";
|
|
39
|
-
if (typeof e === "string") return e;
|
|
40
|
-
if (typeof e !== "object") return String(e);
|
|
41
|
-
const o = e;
|
|
42
|
-
const parts = [];
|
|
43
|
-
if (typeof o.message === "string" && o.message) parts.push(o.message);
|
|
44
|
-
if (typeof o.code === "number") parts.push(`[code: ${o.code}]`);
|
|
45
|
-
if (typeof o.code === "string" && o.code) parts.push(`[code: ${o.code}]`);
|
|
46
|
-
if (typeof o.documentation_url === "string" && o.documentation_url) parts.push(o.documentation_url);
|
|
47
|
-
const src = o.source;
|
|
48
|
-
if (src && typeof src === "object" && "pointer" in src) {
|
|
49
|
-
const p = src.pointer;
|
|
50
|
-
if (typeof p === "string" && p) parts.push(`(field: ${p})`);
|
|
51
|
-
}
|
|
52
|
-
if (Array.isArray(o.error_chain) && o.error_chain.length > 0) parts.push(`[chain: ${o.error_chain.map(describeCloudflareErrorItem).join(" → ")}]`);
|
|
53
|
-
if (parts.length) return parts.join(" ");
|
|
54
|
-
try {
|
|
55
|
-
return JSON.stringify(e);
|
|
56
|
-
} catch {
|
|
57
|
-
return String(e);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function formatCloudflareErrorBody(errors, messages, fallback) {
|
|
61
|
-
const errList = formatCloudflareList(errors) || fallback;
|
|
62
|
-
const msgList = formatCloudflareList(messages);
|
|
63
|
-
if (msgList) return `${errList} — messages: ${msgList}`;
|
|
64
|
-
return errList;
|
|
65
|
-
}
|
|
66
|
-
function formatCloudflareList(v) {
|
|
67
|
-
if (!Array.isArray(v) || v.length === 0) return "";
|
|
68
|
-
return v.map(describeCloudflareErrorItem).join(" | ");
|
|
69
|
-
}
|
|
70
|
-
var CFApiClient = class {
|
|
71
|
-
accountId;
|
|
72
|
-
apiToken;
|
|
73
|
-
constructor(accountId, apiToken) {
|
|
74
|
-
this.accountId = accountId;
|
|
75
|
-
this.apiToken = apiToken ?? cloudflareApiTokenFromEnv();
|
|
76
|
-
if (!this.apiToken) throw new Error("CLOUDFLARE_API_TOKEN is required");
|
|
77
|
-
}
|
|
78
|
-
getAccountId() {
|
|
79
|
-
return this.accountId;
|
|
80
|
-
}
|
|
81
|
-
/** Lightweight account read — validates token + account scope. */
|
|
82
|
-
async accountRead() {
|
|
83
|
-
return (await this.request(`/accounts/${this.accountId}`)).result;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Get a single Worker script by name (account-scoped, **not** dispatch).
|
|
87
|
-
* Returns `undefined` when Cloudflare responds 404 so callers can treat it
|
|
88
|
-
* as "not deployed" without try/catch on the message.
|
|
89
|
-
*
|
|
90
|
-
* @see https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/get/
|
|
91
|
-
*/
|
|
92
|
-
async workersScriptGet(scriptName) {
|
|
93
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/workers/scripts/${encodeURIComponent(scriptName)}`;
|
|
94
|
-
const res = await fetch(url, { headers: {
|
|
95
|
-
Authorization: `Bearer ${this.apiToken}`,
|
|
96
|
-
"Content-Type": "application/json"
|
|
97
|
-
} });
|
|
98
|
-
if (res.status === 404) return void 0;
|
|
99
|
-
const data = await res.json();
|
|
100
|
-
if (!res.ok) {
|
|
101
|
-
const msg = data?.errors?.map((e) => e.message).join("; ") ?? res.statusText;
|
|
102
|
-
throw new Error(`CF API error (workers script get): ${msg}`);
|
|
103
|
-
}
|
|
104
|
-
return data.result;
|
|
105
|
-
}
|
|
106
|
-
async request(path, options = {}) {
|
|
107
|
-
const method = (options.method ?? "GET").toUpperCase();
|
|
108
|
-
const url = `${CF_API_BASE}${path}`;
|
|
109
|
-
const res = await fetch(url, {
|
|
110
|
-
...options,
|
|
111
|
-
headers: {
|
|
112
|
-
Authorization: `Bearer ${this.apiToken}`,
|
|
113
|
-
"Content-Type": "application/json",
|
|
114
|
-
...options.headers
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
let parsed;
|
|
118
|
-
try {
|
|
119
|
-
parsed = await res.json();
|
|
120
|
-
} catch {
|
|
121
|
-
throw new Error(`CF API error: ${method} \`${path}\` → HTTP ${res.status} (response was not valid JSON)`);
|
|
122
|
-
}
|
|
123
|
-
/** Some endpoints (e.g. R2 catalog disable) respond `200` with literal JSON `null`. */
|
|
124
|
-
const data = parsed !== null && typeof parsed === "object" ? parsed : {};
|
|
125
|
-
const httpError = !res.ok;
|
|
126
|
-
const bodySuccessFalse = data.success === false;
|
|
127
|
-
if (httpError || bodySuccessFalse) {
|
|
128
|
-
const detail = formatCloudflareErrorBody(data.errors, data.messages, res.statusText || "no error array in body");
|
|
129
|
-
throw new Error(`CF API error: ${method} \`${path}\` → HTTP ${res.status}. ${detail}`);
|
|
130
|
-
}
|
|
131
|
-
return data;
|
|
132
|
-
}
|
|
133
|
-
async d1ListAll() {
|
|
134
|
-
const all = [];
|
|
135
|
-
let page = 1;
|
|
136
|
-
const perPage = 100;
|
|
137
|
-
while (true) {
|
|
138
|
-
const data = await this.request(`/accounts/${this.accountId}/d1/database?per_page=${perPage}&page=${page}`);
|
|
139
|
-
all.push(...data.result);
|
|
140
|
-
const info = data.result_info;
|
|
141
|
-
if (!info || info.count < perPage) break;
|
|
142
|
-
page++;
|
|
143
|
-
}
|
|
144
|
-
return all;
|
|
145
|
-
}
|
|
146
|
-
async r2ListAll() {
|
|
147
|
-
const all = [];
|
|
148
|
-
const perPage = 100;
|
|
149
|
-
let cursor;
|
|
150
|
-
while (true) {
|
|
151
|
-
const qs = new URLSearchParams({ per_page: String(perPage) });
|
|
152
|
-
if (cursor) qs.set("cursor", cursor);
|
|
153
|
-
const data = await this.request(`/accounts/${this.accountId}/r2/buckets?${qs.toString()}`);
|
|
154
|
-
const buckets = data.result?.buckets ?? [];
|
|
155
|
-
all.push(...buckets.map((b) => ({
|
|
156
|
-
name: b.name ?? "",
|
|
157
|
-
creation_date: b.creation_date ?? ""
|
|
158
|
-
})));
|
|
159
|
-
const next = data.result_info?.cursor;
|
|
160
|
-
if (!next) break;
|
|
161
|
-
cursor = next;
|
|
162
|
-
}
|
|
163
|
-
return all;
|
|
164
|
-
}
|
|
165
|
-
async kvListAll() {
|
|
166
|
-
const all = [];
|
|
167
|
-
let page = 1;
|
|
168
|
-
const perPage = 100;
|
|
169
|
-
while (true) {
|
|
170
|
-
const data = await this.request(`/accounts/${this.accountId}/storage/kv/namespaces?per_page=${perPage}&page=${page}`);
|
|
171
|
-
all.push(...data.result);
|
|
172
|
-
const info = data.result_info;
|
|
173
|
-
if (!info || info.count < perPage) break;
|
|
174
|
-
page++;
|
|
175
|
-
}
|
|
176
|
-
return all;
|
|
177
|
-
}
|
|
178
|
-
async d1Create(name) {
|
|
179
|
-
return (await this.request(`/accounts/${this.accountId}/d1/database`, {
|
|
180
|
-
method: "POST",
|
|
181
|
-
body: JSON.stringify({ name })
|
|
182
|
-
})).result;
|
|
183
|
-
}
|
|
184
|
-
async r2Create(name, location = "auto") {
|
|
185
|
-
await this.request(`/accounts/${this.accountId}/r2/buckets`, {
|
|
186
|
-
method: "POST",
|
|
187
|
-
body: JSON.stringify({
|
|
188
|
-
name,
|
|
189
|
-
location
|
|
190
|
-
})
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
async kvCreate(title) {
|
|
194
|
-
return (await this.request(`/accounts/${this.accountId}/storage/kv/namespaces`, {
|
|
195
|
-
method: "POST",
|
|
196
|
-
body: JSON.stringify({ title })
|
|
197
|
-
})).result;
|
|
198
|
-
}
|
|
199
|
-
async d1Delete(databaseId) {
|
|
200
|
-
await this.request(`/accounts/${this.accountId}/d1/database/${databaseId}`, { method: "DELETE" });
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Run SQL against a D1 database (HTTP API).
|
|
204
|
-
* @see https://developers.cloudflare.com/d1/build-with-d1/rest-api/
|
|
205
|
-
*/
|
|
206
|
-
async d1Query(databaseId, sql, params = []) {
|
|
207
|
-
return { rows: (await this.request(`/accounts/${this.accountId}/d1/database/${databaseId}/query`, {
|
|
208
|
-
method: "POST",
|
|
209
|
-
body: JSON.stringify({
|
|
210
|
-
sql,
|
|
211
|
-
params
|
|
212
|
-
})
|
|
213
|
-
})).result?.[0]?.results ?? [] };
|
|
214
|
-
}
|
|
215
|
-
async r2Delete(bucketName) {
|
|
216
|
-
await this.request(`/accounts/${this.accountId}/r2/buckets/${bucketName}`, { method: "DELETE" });
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Download an object from R2 (HTTP API).
|
|
220
|
-
* @see https://developers.cloudflare.com/api/resources/r2/subresources/buckets/subresources/objects/methods/get/
|
|
221
|
-
*/
|
|
222
|
-
async r2GetObject(bucketName, objectKey) {
|
|
223
|
-
const pathEncoded = objectKey.split("/").map((seg) => encodeURIComponent(seg)).join("/");
|
|
224
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/r2/buckets/${encodeURIComponent(bucketName)}/objects/${pathEncoded}`;
|
|
225
|
-
const res = await fetch(url, { headers: { Authorization: `Bearer ${this.apiToken}` } });
|
|
226
|
-
if (!res.ok) {
|
|
227
|
-
let errMsg = res.statusText;
|
|
228
|
-
try {
|
|
229
|
-
errMsg = (await res.json())?.errors?.map((e) => e.message).join("; ") ?? errMsg;
|
|
230
|
-
} catch {}
|
|
231
|
-
throw new Error(`CF API error (R2 get): ${errMsg}`);
|
|
232
|
-
}
|
|
233
|
-
return res.arrayBuffer();
|
|
234
|
-
}
|
|
235
|
-
async kvDelete(namespaceId) {
|
|
236
|
-
await this.request(`/accounts/${this.accountId}/storage/kv/namespaces/${namespaceId}`, { method: "DELETE" });
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* List every Cloudflare Queue in the account.
|
|
240
|
-
* @see https://developers.cloudflare.com/api/resources/queues/methods/list/
|
|
241
|
-
*/
|
|
242
|
-
async queuesListAll() {
|
|
243
|
-
const all = [];
|
|
244
|
-
let page = 1;
|
|
245
|
-
const perPage = 100;
|
|
246
|
-
while (true) {
|
|
247
|
-
const batch = (await this.request(`/accounts/${this.accountId}/queues?per_page=${perPage}&page=${page}`)).result ?? [];
|
|
248
|
-
all.push(...batch);
|
|
249
|
-
if (batch.length < perPage) break;
|
|
250
|
-
page++;
|
|
251
|
-
}
|
|
252
|
-
return all;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Create a new Cloudflare Queue.
|
|
256
|
-
* @see https://developers.cloudflare.com/api/resources/queues/methods/create/
|
|
257
|
-
*/
|
|
258
|
-
async queueCreate(queueName) {
|
|
259
|
-
return (await this.request(`/accounts/${this.accountId}/queues`, {
|
|
260
|
-
method: "POST",
|
|
261
|
-
body: JSON.stringify({ queue_name: queueName })
|
|
262
|
-
})).result;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Delete a Cloudflare Queue by id.
|
|
266
|
-
* @see https://developers.cloudflare.com/api/resources/queues/methods/delete/
|
|
267
|
-
*/
|
|
268
|
-
async queueDelete(queueId) {
|
|
269
|
-
await this.request(`/accounts/${this.accountId}/queues/${encodeURIComponent(queueId)}`, { method: "DELETE" });
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* List every Hyperdrive config in the account.
|
|
273
|
-
* @see https://developers.cloudflare.com/api/resources/hyperdrive/subresources/configs/methods/list/
|
|
274
|
-
*/
|
|
275
|
-
async hyperdriveListAll() {
|
|
276
|
-
return (await this.request(`/accounts/${this.accountId}/hyperdrive/configs`)).result ?? [];
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Create a Hyperdrive config.
|
|
280
|
-
* @see https://developers.cloudflare.com/api/resources/hyperdrive/subresources/configs/methods/create/
|
|
281
|
-
*/
|
|
282
|
-
async hyperdriveCreate(body) {
|
|
283
|
-
return (await this.request(`/accounts/${this.accountId}/hyperdrive/configs`, {
|
|
284
|
-
method: "POST",
|
|
285
|
-
body: JSON.stringify(body)
|
|
286
|
-
})).result;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Patch an existing Hyperdrive configuration in place. Cloudflare accepts
|
|
290
|
-
* partial updates here (true `PATCH`), so callers may send only the
|
|
291
|
-
* fields that drifted. Origin patches must include the full origin
|
|
292
|
-
* payload (the password is write-only and never returned, so Tamer
|
|
293
|
-
* reads it back from the resource config every apply).
|
|
294
|
-
* @see https://developers.cloudflare.com/api/resources/hyperdrive/subresources/configs/methods/edit/
|
|
295
|
-
*/
|
|
296
|
-
async hyperdrivePatch(configId, body) {
|
|
297
|
-
await this.request(`/accounts/${this.accountId}/hyperdrive/configs/${encodeURIComponent(configId)}`, {
|
|
298
|
-
method: "PATCH",
|
|
299
|
-
body: JSON.stringify(body)
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Delete a Hyperdrive config by id.
|
|
304
|
-
* @see https://developers.cloudflare.com/api/resources/hyperdrive/subresources/configs/methods/delete/
|
|
305
|
-
*/
|
|
306
|
-
async hyperdriveDelete(configId) {
|
|
307
|
-
await this.request(`/accounts/${this.accountId}/hyperdrive/configs/${encodeURIComponent(configId)}`, { method: "DELETE" });
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* List every Vectorize index in the account (v2 storage subsystem).
|
|
311
|
-
* @see https://developers.cloudflare.com/api/resources/vectorize/subresources/indexes/methods/list/
|
|
312
|
-
*/
|
|
313
|
-
async vectorizeListAll() {
|
|
314
|
-
return (await this.request(`/accounts/${this.accountId}/vectorize/v2/indexes`)).result ?? [];
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Create a Vectorize v2 index. `dimensions` and `metric` are immutable.
|
|
318
|
-
* @see https://developers.cloudflare.com/api/resources/vectorize/subresources/indexes/methods/create/
|
|
319
|
-
*/
|
|
320
|
-
async vectorizeCreate(body) {
|
|
321
|
-
return (await this.request(`/accounts/${this.accountId}/vectorize/v2/indexes`, {
|
|
322
|
-
method: "POST",
|
|
323
|
-
body: JSON.stringify(body)
|
|
324
|
-
})).result;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Delete a Vectorize index by name.
|
|
328
|
-
* @see https://developers.cloudflare.com/api/resources/vectorize/subresources/indexes/methods/delete/
|
|
329
|
-
*/
|
|
330
|
-
async vectorizeDelete(indexName) {
|
|
331
|
-
await this.request(`/accounts/${this.accountId}/vectorize/v2/indexes/${encodeURIComponent(indexName)}`, { method: "DELETE" });
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* List every AI Gateway in the account.
|
|
335
|
-
* @see https://developers.cloudflare.com/api/resources/ai_gateway/methods/list/
|
|
336
|
-
*/
|
|
337
|
-
async aiGatewayListAll() {
|
|
338
|
-
return (await this.request(`/accounts/${this.accountId}/ai-gateway/gateways?per_page=100`)).result ?? [];
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Create an AI Gateway. The gateway `id` is user-supplied and acts as both
|
|
342
|
-
* primary key and routing slug under `https://gateway.ai.cloudflare.com/`.
|
|
343
|
-
* @see https://developers.cloudflare.com/api/resources/ai_gateway/methods/create/
|
|
344
|
-
*/
|
|
345
|
-
async aiGatewayCreate(body) {
|
|
346
|
-
return (await this.request(`/accounts/${this.accountId}/ai-gateway/gateways`, {
|
|
347
|
-
method: "POST",
|
|
348
|
-
body: JSON.stringify(body)
|
|
349
|
-
})).result;
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Update an existing AI Gateway in place. The Cloudflare API uses `PUT`
|
|
353
|
-
* (not PATCH) and is full-replace on the listed fields, so callers must
|
|
354
|
-
* supply the complete desired state — Tamer's `apply` reads the recorded
|
|
355
|
-
* state row and merges declared overrides before calling this.
|
|
356
|
-
* @see https://developers.cloudflare.com/api/resources/ai_gateway/methods/update/
|
|
357
|
-
*/
|
|
358
|
-
async aiGatewayUpdate(gatewayId, body) {
|
|
359
|
-
await this.request(`/accounts/${this.accountId}/ai-gateway/gateways/${encodeURIComponent(gatewayId)}`, {
|
|
360
|
-
method: "PUT",
|
|
361
|
-
body: JSON.stringify(body)
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Delete an AI Gateway by id.
|
|
366
|
-
* @see https://developers.cloudflare.com/api/resources/ai_gateway/methods/delete/
|
|
367
|
-
*/
|
|
368
|
-
async aiGatewayDelete(gatewayId) {
|
|
369
|
-
await this.request(`/accounts/${this.accountId}/ai-gateway/gateways/${encodeURIComponent(gatewayId)}`, { method: "DELETE" });
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* List every Pipeline in the account (paginated, 100/page). Uses the V1
|
|
373
|
-
* SQL pipelines endpoint; the deprecated `/accounts/{id}/pipelines`
|
|
374
|
-
* (HTTP/binding sources) is not used.
|
|
375
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/methods/list_v1/
|
|
376
|
-
*/
|
|
377
|
-
async pipelineListAll() {
|
|
378
|
-
const all = [];
|
|
379
|
-
let page = 1;
|
|
380
|
-
const perPage = 100;
|
|
381
|
-
while (true) {
|
|
382
|
-
const batch = (await this.request(`/accounts/${this.accountId}/pipelines/v1/pipelines?per_page=${perPage}&page=${page}`)).result ?? [];
|
|
383
|
-
all.push(...batch);
|
|
384
|
-
if (batch.length < perPage) break;
|
|
385
|
-
page += 1;
|
|
386
|
-
}
|
|
387
|
-
return all;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Create a Pipeline. Server assigns the `id`; `name` is user-supplied
|
|
391
|
-
* and uniquely identifies the pipeline within the account.
|
|
392
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/methods/create_v1/
|
|
393
|
-
*/
|
|
394
|
-
async pipelineCreate(body) {
|
|
395
|
-
return (await this.request(`/accounts/${this.accountId}/pipelines/v1/pipelines`, {
|
|
396
|
-
method: "POST",
|
|
397
|
-
body: JSON.stringify(body)
|
|
398
|
-
})).result;
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* Delete a Pipeline by server-assigned id.
|
|
402
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/methods/delete_v1/
|
|
403
|
-
*/
|
|
404
|
-
async pipelineDelete(pipelineId) {
|
|
405
|
-
const pathId = pipelinesV1IdForPath(pipelineId);
|
|
406
|
-
await this.request(`/accounts/${this.accountId}/pipelines/v1/pipelines/${encodeURIComponent(pathId)}`, { method: "DELETE" });
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/streams/methods/list/
|
|
410
|
-
*/
|
|
411
|
-
async pipelinesV1StreamListAll() {
|
|
412
|
-
const all = [];
|
|
413
|
-
let page = 1;
|
|
414
|
-
const perPage = 100;
|
|
415
|
-
while (true) {
|
|
416
|
-
const batch = (await this.request(`/accounts/${this.accountId}/pipelines/v1/streams?per_page=${perPage}&page=${page}`)).result ?? [];
|
|
417
|
-
all.push(...batch);
|
|
418
|
-
if (batch.length < perPage) break;
|
|
419
|
-
page += 1;
|
|
420
|
-
}
|
|
421
|
-
return all;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/streams/methods/create/
|
|
425
|
-
*/
|
|
426
|
-
async pipelinesV1StreamCreate(body) {
|
|
427
|
-
return (await this.request(`/accounts/${this.accountId}/pipelines/v1/streams`, {
|
|
428
|
-
method: "POST",
|
|
429
|
-
body: JSON.stringify(body)
|
|
430
|
-
})).result;
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Path id: 32 lower-case hex chars (no hyphens). The dashboard issues a
|
|
434
|
-
* plain `DELETE` with no query string; pass `{ force: true }` only if the API
|
|
435
|
-
* docs require it for your case.
|
|
436
|
-
*
|
|
437
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/streams/methods/delete/
|
|
438
|
-
*/
|
|
439
|
-
async pipelinesV1StreamDelete(streamId, query) {
|
|
440
|
-
const pathId = pipelinesV1IdForPath(streamId);
|
|
441
|
-
const qs = new URLSearchParams();
|
|
442
|
-
if (query?.force) qs.set("force", "true");
|
|
443
|
-
const tail = qs.toString() ? `?${qs.toString()}` : "";
|
|
444
|
-
await this.request(`/accounts/${this.accountId}/pipelines/v1/streams/${encodeURIComponent(pathId)}${tail}`, { method: "DELETE" });
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/sinks/methods/list/
|
|
448
|
-
*/
|
|
449
|
-
async pipelinesV1SinkListAll() {
|
|
450
|
-
const all = [];
|
|
451
|
-
let page = 1;
|
|
452
|
-
const perPage = 100;
|
|
453
|
-
while (true) {
|
|
454
|
-
const batch = (await this.request(`/accounts/${this.accountId}/pipelines/v1/sinks?per_page=${perPage}&page=${page}`)).result ?? [];
|
|
455
|
-
all.push(...batch);
|
|
456
|
-
if (batch.length < perPage) break;
|
|
457
|
-
page += 1;
|
|
458
|
-
}
|
|
459
|
-
return all;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* R2 Data Catalog sink `config` includes `table_name` and `namespace` as
|
|
463
|
-
* Cloudflare has registered them (may differ from the name sent at create).
|
|
464
|
-
*
|
|
465
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/sinks/methods/get/
|
|
466
|
-
*/
|
|
467
|
-
async pipelinesV1SinkGet(sinkId) {
|
|
468
|
-
const pathId = pipelinesV1IdForPath(sinkId);
|
|
469
|
-
return (await this.request(`/accounts/${this.accountId}/pipelines/v1/sinks/${encodeURIComponent(pathId)}`)).result;
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/sinks/methods/create/
|
|
473
|
-
*/
|
|
474
|
-
async pipelinesV1SinkCreate(body) {
|
|
475
|
-
return (await this.request(`/accounts/${this.accountId}/pipelines/v1/sinks`, {
|
|
476
|
-
method: "POST",
|
|
477
|
-
body: JSON.stringify(body)
|
|
478
|
-
})).result;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Path id: 32 lower-case hex chars (no hyphens). Optional `{ force: true }`
|
|
482
|
-
* matches `?force=true` when the product requires it (e.g. some sink types).
|
|
483
|
-
*
|
|
484
|
-
* @see https://developers.cloudflare.com/api/resources/pipelines/subresources/sinks/methods/delete/
|
|
485
|
-
*/
|
|
486
|
-
async pipelinesV1SinkDelete(sinkId, query) {
|
|
487
|
-
const pathId = pipelinesV1IdForPath(sinkId);
|
|
488
|
-
const qs = new URLSearchParams();
|
|
489
|
-
if (query?.force) qs.set("force", "true");
|
|
490
|
-
const tail = qs.toString() ? `?${qs.toString()}` : "";
|
|
491
|
-
await this.request(`/accounts/${this.accountId}/pipelines/v1/sinks/${encodeURIComponent(pathId)}${tail}`, { method: "DELETE" });
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* @see https://developers.cloudflare.com/api/resources/r2_data_catalog/methods/list/
|
|
495
|
-
*/
|
|
496
|
-
async r2DataCatalogList() {
|
|
497
|
-
return { warehouses: (await this.request(`/accounts/${this.accountId}/r2-catalog`)).result?.warehouses ?? [] };
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* @see https://developers.cloudflare.com/api/resources/r2_data_catalog/methods/enable/
|
|
501
|
-
*/
|
|
502
|
-
async r2DataCatalogEnable(bucketName) {
|
|
503
|
-
await this.request(`/accounts/${this.accountId}/r2-catalog/${encodeURIComponent(bucketName)}/enable`, { method: "POST" });
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* @see https://developers.cloudflare.com/api/resources/r2_data_catalog/methods/update/
|
|
507
|
-
* (Store catalog credentials)
|
|
508
|
-
*/
|
|
509
|
-
async r2DataCatalogStoreCredential(bucketName, token) {
|
|
510
|
-
await this.request(`/accounts/${this.accountId}/r2-catalog/${encodeURIComponent(bucketName)}/credential`, {
|
|
511
|
-
method: "POST",
|
|
512
|
-
body: JSON.stringify({ token })
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Deactivates the R2 Data Catalog for a bucket (metadata files remain in R2
|
|
517
|
-
* until the bucket is emptied or objects are removed). Next `apply` will
|
|
518
|
-
* re-enable the catalog as part of `pipelinesAuto` when needed.
|
|
519
|
-
*
|
|
520
|
-
* @see https://developers.cloudflare.com/api/resources/r2_data_catalog/methods/disable/
|
|
521
|
-
*/
|
|
522
|
-
async r2DataCatalogDisable(bucketName) {
|
|
523
|
-
await this.request(`/accounts/${this.accountId}/r2-catalog/${encodeURIComponent(bucketName)}/disable`, { method: "POST" });
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* List every Workflow registered on the account (paginated, 100/page).
|
|
527
|
-
* Cloudflare returns the configured class + script binding plus
|
|
528
|
-
* aggregate instance counts; we only consume the registration metadata.
|
|
529
|
-
* @see https://developers.cloudflare.com/api/resources/workflows/methods/list/
|
|
530
|
-
*/
|
|
531
|
-
async workflowListAll() {
|
|
532
|
-
const all = [];
|
|
533
|
-
let page = 1;
|
|
534
|
-
while (true) {
|
|
535
|
-
const data = await this.request(`/accounts/${this.accountId}/workflows?page=${page}&per_page=100`);
|
|
536
|
-
const batch = data.result ?? [];
|
|
537
|
-
all.push(...batch);
|
|
538
|
-
const totalPages = data.result_info?.total_pages ?? 1;
|
|
539
|
-
if (page >= totalPages || batch.length === 0) break;
|
|
540
|
-
page += 1;
|
|
541
|
-
}
|
|
542
|
-
return all;
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Create or update a Workflow registration. Cloudflare's `PUT` is upsert:
|
|
546
|
-
* if `workflow_name` exists it patches `class_name` / `script_name` /
|
|
547
|
-
* `limits`, otherwise it creates a new one. The bound class must already
|
|
548
|
-
* be deployed in `script_name`'s code (PUT against an unknown class
|
|
549
|
-
* succeeds at registration time but fails at first instance create).
|
|
550
|
-
* @see https://developers.cloudflare.com/api/resources/workflows/methods/update/
|
|
551
|
-
*/
|
|
552
|
-
async workflowUpsert(name, body) {
|
|
553
|
-
return (await this.request(`/accounts/${this.accountId}/workflows/${encodeURIComponent(name)}`, {
|
|
554
|
-
method: "PUT",
|
|
555
|
-
body: JSON.stringify(body)
|
|
556
|
-
})).result;
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* Delete a Workflow registration by name. Per Cloudflare's docs this only
|
|
560
|
-
* removes the workflow itself — the worker that hosts the class is
|
|
561
|
-
* untouched and existing in-flight instances continue to run.
|
|
562
|
-
* @see https://developers.cloudflare.com/api/resources/workflows/methods/delete/
|
|
563
|
-
*/
|
|
564
|
-
async workflowDelete(name) {
|
|
565
|
-
await this.request(`/accounts/${this.accountId}/workflows/${encodeURIComponent(name)}`, { method: "DELETE" });
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* List every Secrets Store store on the account (paginated, 100/page).
|
|
569
|
-
* Stores are account-scoped containers; their internal secret entries
|
|
570
|
-
* are listed via {@link secretsStoreSecretListAll}.
|
|
571
|
-
* @see https://developers.cloudflare.com/api/resources/secrets_store/subresources/stores/methods/list/
|
|
572
|
-
*/
|
|
573
|
-
async secretsStoreListAll() {
|
|
574
|
-
const all = [];
|
|
575
|
-
let page = 1;
|
|
576
|
-
while (true) {
|
|
577
|
-
const data = await this.request(`/accounts/${this.accountId}/secrets_store/stores?page=${page}&per_page=100`);
|
|
578
|
-
const batch = data.result ?? [];
|
|
579
|
-
all.push(...batch);
|
|
580
|
-
const totalPages = data.result_info?.total_pages ?? 1;
|
|
581
|
-
if (page >= totalPages || batch.length === 0) break;
|
|
582
|
-
page += 1;
|
|
583
|
-
}
|
|
584
|
-
return all;
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Create a new Secrets Store. Per the API a store name uniquely identifies
|
|
588
|
-
* the container within an account but is **not** itself a primary key —
|
|
589
|
-
* the assigned `id` is. Tamer enforces uniqueness via the derived
|
|
590
|
-
* `sec-{logical}-t-{tenantId}-{env}` name and short-circuits to the
|
|
591
|
-
* existing id when it finds a match in `secretsStoreListAll`.
|
|
592
|
-
* @see https://developers.cloudflare.com/api/resources/secrets_store/subresources/stores/methods/create/
|
|
593
|
-
*/
|
|
594
|
-
async secretsStoreCreate(name) {
|
|
595
|
-
return (await this.request(`/accounts/${this.accountId}/secrets_store/stores`, {
|
|
596
|
-
method: "POST",
|
|
597
|
-
body: JSON.stringify({ name })
|
|
598
|
-
})).result;
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Delete a Secrets Store by id. Cloudflare cascades the deletion to all
|
|
602
|
-
* secrets inside the store, so callers should ensure no live worker is
|
|
603
|
-
* still binding into this store before invoking.
|
|
604
|
-
* @see https://developers.cloudflare.com/api/resources/secrets_store/subresources/stores/methods/delete/
|
|
605
|
-
*/
|
|
606
|
-
async secretsStoreDelete(storeId) {
|
|
607
|
-
await this.request(`/accounts/${this.accountId}/secrets_store/stores/${encodeURIComponent(storeId)}`, { method: "DELETE" });
|
|
608
|
-
}
|
|
609
|
-
async dispatchNamespaceListAll() {
|
|
610
|
-
return (await this.request(`/accounts/${this.accountId}/workers/dispatch/namespaces`)).result ?? [];
|
|
611
|
-
}
|
|
612
|
-
async dispatchNamespaceCreate(namespaceName) {
|
|
613
|
-
await this.request(`/accounts/${this.accountId}/workers/dispatch/namespaces`, {
|
|
614
|
-
method: "POST",
|
|
615
|
-
body: JSON.stringify({ name: namespaceName })
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
async dispatchNamespaceDelete(namespaceName) {
|
|
619
|
-
await this.request(`/accounts/${this.accountId}/workers/dispatch/namespaces/${encodeURIComponent(namespaceName)}`, { method: "DELETE" });
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Upload a user Worker module to a Workers for Platforms dispatch namespace (multipart).
|
|
623
|
-
* @see https://developers.cloudflare.com/api/operations/namespace-worker-script-upload-worker-module
|
|
624
|
-
*/
|
|
625
|
-
async dispatchNamespaceScriptPut(dispatchNamespace, scriptName, formData) {
|
|
626
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/workers/dispatch/namespaces/${encodeURIComponent(dispatchNamespace)}/scripts/${encodeURIComponent(scriptName)}`;
|
|
627
|
-
const res = await fetch(url, {
|
|
628
|
-
method: "PUT",
|
|
629
|
-
headers: { Authorization: `Bearer ${this.apiToken}` },
|
|
630
|
-
body: formData
|
|
631
|
-
});
|
|
632
|
-
const data = await res.json();
|
|
633
|
-
if (!res.ok) {
|
|
634
|
-
const errMsg = data?.errors?.map((e) => e.message).join("; ") ?? res.statusText;
|
|
635
|
-
throw new Error(`CF API error: ${errMsg}`);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* List every script inside a dispatch namespace.
|
|
640
|
-
* @see https://developers.cloudflare.com/api/resources/workers_for_platforms/subresources/dispatch/subresources/namespaces/subresources/scripts/methods/list/
|
|
641
|
-
*/
|
|
642
|
-
async dispatchNamespaceScriptList(dispatchNamespace) {
|
|
643
|
-
return (await this.request(`/accounts/${this.accountId}/workers/dispatch/namespaces/${encodeURIComponent(dispatchNamespace)}/scripts`)).result ?? [];
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* Remove a script from a Workers for Platforms dispatch namespace.
|
|
647
|
-
* @see https://developers.cloudflare.com/api/resources/workers_for_platforms/subresources/dispatch/subresources/namespaces/subresources/scripts/methods/delete/
|
|
648
|
-
*/
|
|
649
|
-
async dispatchNamespaceScriptDelete(dispatchNamespace, scriptName, options) {
|
|
650
|
-
const q = options?.force ? "?force=true" : "";
|
|
651
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/workers/dispatch/namespaces/${encodeURIComponent(dispatchNamespace)}/scripts/${encodeURIComponent(scriptName)}${q}`;
|
|
652
|
-
const res = await fetch(url, {
|
|
653
|
-
method: "DELETE",
|
|
654
|
-
headers: { Authorization: `Bearer ${this.apiToken}` }
|
|
655
|
-
});
|
|
656
|
-
if (!res.ok) {
|
|
657
|
-
let errMsg = res.statusText;
|
|
658
|
-
try {
|
|
659
|
-
errMsg = (await res.json())?.errors?.map((e) => e.message).join("; ") ?? errMsg;
|
|
660
|
-
} catch {}
|
|
661
|
-
throw new Error(`CF API error: ${errMsg}`);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* @see https://developers.cloudflare.com/api/resources/workers/subresources/routes/methods/list/
|
|
666
|
-
*/
|
|
667
|
-
async zoneWorkerRoutesList(zoneId) {
|
|
668
|
-
return (await this.request(`/zones/${zoneId}/workers/routes`)).result ?? [];
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* @see https://developers.cloudflare.com/api/resources/workers/subresources/routes/methods/create/
|
|
672
|
-
*/
|
|
673
|
-
async zoneWorkerRouteCreate(zoneId, body) {
|
|
674
|
-
return (await this.request(`/zones/${zoneId}/workers/routes`, {
|
|
675
|
-
method: "POST",
|
|
676
|
-
body: JSON.stringify(body)
|
|
677
|
-
})).result;
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* @see https://developers.cloudflare.com/api/resources/workers/subresources/routes/methods/delete/
|
|
681
|
-
*/
|
|
682
|
-
async zoneWorkerRouteDelete(zoneId, routeId) {
|
|
683
|
-
await this.request(`/zones/${zoneId}/workers/routes/${encodeURIComponent(routeId)}`, { method: "DELETE" });
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* List every DNS record on a zone (paginated, 100/page). Returns the
|
|
687
|
-
* subset of fields Tamer cares about — the full Cloudflare object also
|
|
688
|
-
* carries `meta`, `proxiable`, `created_on`, `modified_on`, etc., none of
|
|
689
|
-
* which we persist in state.
|
|
690
|
-
*
|
|
691
|
-
* @see https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/
|
|
692
|
-
*/
|
|
693
|
-
async zoneDnsRecordListAll(zoneId) {
|
|
694
|
-
const all = [];
|
|
695
|
-
let page = 1;
|
|
696
|
-
while (true) {
|
|
697
|
-
const data = await this.request(`/zones/${zoneId}/dns_records?page=${page}&per_page=100`);
|
|
698
|
-
const batch = data.result ?? [];
|
|
699
|
-
all.push(...batch);
|
|
700
|
-
const totalPages = data.result_info?.total_pages ?? 1;
|
|
701
|
-
if (page >= totalPages || batch.length === 0) break;
|
|
702
|
-
page += 1;
|
|
703
|
-
}
|
|
704
|
-
return all;
|
|
705
|
-
}
|
|
706
|
-
/**
|
|
707
|
-
* Create a DNS record on a zone. The Cloudflare API rejects duplicate
|
|
708
|
-
* `(type, name, content)` triples for record types where that combination
|
|
709
|
-
* is meaningful (CNAME, A, AAAA), so callers should pre-check via
|
|
710
|
-
* {@link zoneDnsRecordListAll}.
|
|
711
|
-
*
|
|
712
|
-
* @see https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/create/
|
|
713
|
-
*/
|
|
714
|
-
async zoneDnsRecordCreate(zoneId, body) {
|
|
715
|
-
return (await this.request(`/zones/${zoneId}/dns_records`, {
|
|
716
|
-
method: "POST",
|
|
717
|
-
body: JSON.stringify(body)
|
|
718
|
-
})).result;
|
|
719
|
-
}
|
|
720
|
-
/**
|
|
721
|
-
* Patch a DNS record in place. Cloudflare's PATCH endpoint accepts any
|
|
722
|
-
* subset of mutable fields (`content`, `ttl`, `proxied`, `priority`,
|
|
723
|
-
* `comment`) but rejects `type` changes — Tamer falls back to
|
|
724
|
-
* delete-and-recreate when the type drifts.
|
|
725
|
-
*
|
|
726
|
-
* @see https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/edit/
|
|
727
|
-
*/
|
|
728
|
-
async zoneDnsRecordPatch(zoneId, recordId, body) {
|
|
729
|
-
await this.request(`/zones/${zoneId}/dns_records/${encodeURIComponent(recordId)}`, {
|
|
730
|
-
method: "PATCH",
|
|
731
|
-
body: JSON.stringify(body)
|
|
732
|
-
});
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* @see https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/
|
|
736
|
-
*/
|
|
737
|
-
async zoneDnsRecordDelete(zoneId, recordId) {
|
|
738
|
-
await this.request(`/zones/${zoneId}/dns_records/${encodeURIComponent(recordId)}`, { method: "DELETE" });
|
|
739
|
-
}
|
|
740
|
-
/**
|
|
741
|
-
* Look up zones by exact name.
|
|
742
|
-
*
|
|
743
|
-
* Account-scoped tokens with `Zone Read` see every zone under the account.
|
|
744
|
-
* Returns an array because Cloudflare allows the same name across accounts;
|
|
745
|
-
* the caller normally takes `[0]`.
|
|
746
|
-
*
|
|
747
|
-
* @see https://developers.cloudflare.com/api/operations/zones-get
|
|
748
|
-
*/
|
|
749
|
-
async zonesListByName(name) {
|
|
750
|
-
const qs = new URLSearchParams({
|
|
751
|
-
name,
|
|
752
|
-
"account.id": this.accountId,
|
|
753
|
-
per_page: "50"
|
|
754
|
-
});
|
|
755
|
-
return (await this.request(`/zones?${qs.toString()}`)).result ?? [];
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* List account-scoped Logpush jobs (includes `workers_trace_events`).
|
|
759
|
-
* @see https://developers.cloudflare.com/api/resources/logpush/subresources/jobs/methods/list/
|
|
760
|
-
*/
|
|
761
|
-
async logpushAccountJobsList() {
|
|
762
|
-
return (await this.request(`/accounts/${this.accountId}/logpush/jobs`)).result ?? [];
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Fetch one account-scoped Logpush job (includes `destination_conf`).
|
|
766
|
-
* @see https://developers.cloudflare.com/api/resources/logpush/subresources/jobs/methods/get/
|
|
767
|
-
*/
|
|
768
|
-
async logpushAccountJobGet(jobId) {
|
|
769
|
-
const data = await this.request(`/accounts/${this.accountId}/logpush/jobs/${jobId}`);
|
|
770
|
-
if (!data.result?.id) throw new Error(`Logpush job GET ${jobId}: missing result (job may not exist on this account)`);
|
|
771
|
-
return data.result;
|
|
772
|
-
}
|
|
773
|
-
/**
|
|
774
|
-
* Create an account Logpush job. Caller supplies `destination_conf` and dataset.
|
|
775
|
-
* @see https://developers.cloudflare.com/api/resources/logpush/subresources/jobs/methods/create/
|
|
776
|
-
*/
|
|
777
|
-
async logpushAccountJobCreate(body) {
|
|
778
|
-
return (await this.request(`/accounts/${this.accountId}/logpush/jobs`, {
|
|
779
|
-
method: "POST",
|
|
780
|
-
body: JSON.stringify(body)
|
|
781
|
-
})).result;
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Update mutable Logpush job fields in place.
|
|
785
|
-
* @see https://developers.cloudflare.com/api/resources/logpush/subresources/jobs/methods/update/
|
|
786
|
-
*/
|
|
787
|
-
async logpushAccountJobUpdate(jobId, body) {
|
|
788
|
-
await this.request(`/accounts/${this.accountId}/logpush/jobs/${jobId}`, {
|
|
789
|
-
method: "PUT",
|
|
790
|
-
body: JSON.stringify(body)
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Delete a Logpush job by numeric id.
|
|
795
|
-
* @see https://developers.cloudflare.com/api/resources/logpush/subresources/jobs/methods/delete/
|
|
796
|
-
*/
|
|
797
|
-
async logpushAccountJobDelete(jobId) {
|
|
798
|
-
await this.request(`/accounts/${this.accountId}/logpush/jobs/${jobId}`, { method: "DELETE" });
|
|
799
|
-
}
|
|
800
|
-
/**
|
|
801
|
-
* List all permission groups for account-owned API tokens (paginated).
|
|
802
|
-
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/subresources/permission_groups/methods/list/
|
|
803
|
-
*/
|
|
804
|
-
async accountTokenPermissionGroupsListAll() {
|
|
805
|
-
const all = [];
|
|
806
|
-
const seen = /* @__PURE__ */ new Set();
|
|
807
|
-
let page = 1;
|
|
808
|
-
const perPage = 100;
|
|
809
|
-
/** Failsafe: pagination must always terminate even if the API omits `total_count` or repeats pages. */
|
|
810
|
-
const maxPage = 500;
|
|
811
|
-
while (true) {
|
|
812
|
-
if (page > maxPage) throw new Error(`Account token permission groups: exceeded ${maxPage} pages (partial count ${all.length}) — refusing to paginate further (check Cloudflare API or file a bug)`);
|
|
813
|
-
const data = await this.request(`/accounts/${this.accountId}/tokens/permission_groups?per_page=${perPage}&page=${page}`);
|
|
814
|
-
const batch = data.result ?? [];
|
|
815
|
-
if (batch.length === 0) break;
|
|
816
|
-
const newRows = batch.filter((g) => g.id && !seen.has(g.id));
|
|
817
|
-
for (const g of newRows) seen.add(g.id);
|
|
818
|
-
if (newRows.length === 0) break;
|
|
819
|
-
all.push(...newRows);
|
|
820
|
-
if (batch.length < perPage) break;
|
|
821
|
-
const total = data.result_info?.total_count;
|
|
822
|
-
if (typeof total === "number" && all.length >= total) break;
|
|
823
|
-
page++;
|
|
824
|
-
}
|
|
825
|
-
return all;
|
|
826
|
-
}
|
|
827
|
-
/**
|
|
828
|
-
* List all account-owned API tokens (paginated).
|
|
829
|
-
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/methods/list/
|
|
830
|
-
*/
|
|
831
|
-
async accountTokenListAll() {
|
|
832
|
-
const all = [];
|
|
833
|
-
let page = 1;
|
|
834
|
-
const perPage = 50;
|
|
835
|
-
const maxPage = 500;
|
|
836
|
-
while (page <= maxPage) {
|
|
837
|
-
const data = await this.request(`/accounts/${this.accountId}/tokens?per_page=${perPage}&page=${page}`);
|
|
838
|
-
const batch = data.result ?? [];
|
|
839
|
-
all.push(...batch);
|
|
840
|
-
const total = data.result_info?.total_count;
|
|
841
|
-
if (typeof total === "number" && all.length >= total) break;
|
|
842
|
-
if (batch.length < perPage) break;
|
|
843
|
-
page += 1;
|
|
844
|
-
}
|
|
845
|
-
return all;
|
|
846
|
-
}
|
|
847
|
-
/**
|
|
848
|
-
* Create an account-owned API token. `result.value` is only returned on create.
|
|
849
|
-
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/methods/create/
|
|
850
|
-
*/
|
|
851
|
-
async accountTokenCreate(body) {
|
|
852
|
-
return (await this.request(`/accounts/${this.accountId}/tokens`, {
|
|
853
|
-
method: "POST",
|
|
854
|
-
body: JSON.stringify(body)
|
|
855
|
-
})).result;
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Delete (revoke) an account-owned API token.
|
|
859
|
-
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/methods/delete/
|
|
860
|
-
*/
|
|
861
|
-
async accountTokenDelete(tokenId) {
|
|
862
|
-
await this.request(`/accounts/${this.accountId}/tokens/${encodeURIComponent(tokenId)}`, { method: "DELETE" });
|
|
863
|
-
}
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
//#endregion
|
|
867
|
-
export { cloudflareAccountIdFromEnv as n, cloudflareApiTokenFromEnv as r, CFApiClient as t };
|
|
868
|
-
//# sourceMappingURL=CFApiClient-DhbyyV71.mjs.map
|