@@ -2,13 +2,15 @@ import "dotenv/config";
22
33const zoneId = process . env . CF_ZONE_ID ;
44const apiToken = process . env . CF_API_TOKEN ;
5+ const kvNamespaceId = process . env . CF_KV_NAMESPACE_ID ;
56
67if ( ! 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