Skip to content

Commit ea56bc2

Browse files
committed
add KV namespace purge to cache purge script
1 parent f20866c commit ea56bc2

1 file changed

Lines changed: 69 additions & 5 deletions

File tree

scripts/cache-purge.ts

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import "dotenv/config";
22

33
const zoneId = process.env.CF_ZONE_ID;
44
const apiToken = process.env.CF_API_TOKEN;
5+
const kvNamespaceId = process.env.CF_KV_NAMESPACE_ID;
56

67
if (!zoneId || !apiToken) {
78
console.error("Missing CF_ZONE_ID or CF_API_TOKEN environment variables");
89
process.exit(1);
910
}
1011

11-
const response = await fetch(
12+
// Purge Cloudflare edge cache
13+
const cacheResponse = await fetch(
1214
`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
1315
{
1416
method: "POST",
@@ -20,11 +22,73 @@ const response = await fetch(
2022
},
2123
);
2224

23-
const result = await response.json();
25+
const cacheResult = await cacheResponse.json();
2426

25-
if (result.success) {
26-
console.log("Cache purged successfully");
27+
if (cacheResult.success) {
28+
console.log("Edge cache purged");
2729
} else {
28-
console.error("Cache purge failed:", result.errors);
30+
console.error("Edge cache purge failed:", cacheResult.errors);
2931
process.exit(1);
3032
}
33+
34+
// Purge KV namespace
35+
if (!kvNamespaceId) {
36+
console.log("No CF_KV_NAMESPACE_ID set, skipping KV purge");
37+
} else {
38+
const accountId = process.env.CF_ACCOUNT_ID;
39+
if (!accountId) {
40+
console.error("Missing CF_ACCOUNT_ID for KV purge");
41+
process.exit(1);
42+
}
43+
44+
// List all keys
45+
let cursor: string | undefined;
46+
const allKeys: string[] = [];
47+
48+
do {
49+
const params = new URLSearchParams();
50+
if (cursor) params.set("cursor", cursor);
51+
52+
const listRes = await fetch(
53+
`https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${kvNamespaceId}/keys?${params}`,
54+
{ headers: { Authorization: `Bearer ${apiToken}` } },
55+
);
56+
57+
const listData: any = await listRes.json();
58+
if (!listData.success) {
59+
console.error("KV list failed:", listData.errors);
60+
process.exit(1);
61+
}
62+
63+
allKeys.push(...listData.result.map((k: { name: string }) => k.name));
64+
cursor = listData.result_info?.cursor;
65+
} while (cursor);
66+
67+
if (allKeys.length === 0) {
68+
console.log("KV namespace empty, nothing to purge");
69+
} else {
70+
// Bulk delete (max 10,000 per request)
71+
for (let i = 0; i < allKeys.length; i += 10000) {
72+
const batch = allKeys.slice(i, i + 10000);
73+
const delRes = await fetch(
74+
`https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${kvNamespaceId}/bulk`,
75+
{
76+
method: "DELETE",
77+
headers: {
78+
Authorization: `Bearer ${apiToken}`,
79+
"Content-Type": "application/json",
80+
},
81+
body: JSON.stringify(batch),
82+
},
83+
);
84+
85+
const delData: any = await delRes.json();
86+
if (!delData.success) {
87+
console.error("KV bulk delete failed:", delData.errors);
88+
process.exit(1);
89+
}
90+
}
91+
92+
console.log(`KV purged: ${allKeys.length} keys deleted`);
93+
}
94+
}

0 commit comments

Comments
 (0)