# Cache Reserve API

## Workers Integration

Cache Reserve works automatically with Workers Cache API, but requires specific patterns:

### Standard Fetch (Recommended)

```typescript
// Cache Reserve works automatically via standard fetch
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Standard fetch uses Cache Reserve automatically
    return await fetch(request);
  }
};
```

### Cache API Limitations

**IMPORTANT**: `cache.put()` is **NOT compatible** with Cache Reserve or Tiered Cache.

```typescript
// ❌ WRONG: cache.put() bypasses Cache Reserve
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
  response = await fetch(request);
  await cache.put(request, response.clone()); // Bypasses Cache Reserve!
}

// ✅ CORRECT: Use standard fetch for Cache Reserve compatibility
return await fetch(request);

// ✅ CORRECT: Use Cache API only for custom cache namespaces
const customCache = await caches.open('my-custom-cache');
let response = await customCache.match(request);
if (!response) {
  response = await fetch(request);
  await customCache.put(request, response.clone()); // Custom cache OK
}
```

## Purging and Cache Management

### Purge by URL (Instant)

```typescript
// Purge specific URL from Cache Reserve immediately
const purgeCacheReserveByURL = async (
  zoneId: string,
  apiToken: string,
  urls: string[]
) => {
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiToken}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ files: urls })
    }
  );
  return await response.json();
};

// Example usage
await purgeCacheReserveByURL('zone123', 'token456', [
  'https://example.com/image.jpg',
  'https://example.com/video.mp4'
]);
```

### Purge by Tag/Host/Prefix (Revalidation)

```typescript
// Purge by cache tag - forces revalidation, not immediate removal
const purgeCacheReserveByTag = async (
  zoneId: string,
  apiToken: string,
  tags: string[]
) => {
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiToken}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ tags })
    }
  );
  return await response.json();
};

// Note: Assets remain in Cache Reserve but will revalidate on next request
// Storage costs continue until retention TTL expires
```

**Important purge behavior differences:**

- **Purge by URL**: Immediately removes from Cache Reserve + edge cache
- **Purge by tag/host/prefix**: Forces revalidation but assets remain in storage
- **Storage costs**: Continue for tag/host/prefix purges until TTL expiry

### Clear All Cache Reserve Data

```typescript
// Clear ALL Cache Reserve data (requires Cache Reserve to be OFF)
const clearAllCacheReserve = async (zoneId: string, apiToken: string) => {
  // Step 1: Verify Cache Reserve is off
  const statusResponse = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${zoneId}/cache/cache_reserve`,
    { method: 'GET', headers: { 'Authorization': `Bearer ${apiToken}` } }
  );
  const status = await statusResponse.json();
  
  if (status.result.value !== 'off') {
    throw new Error('Cache Reserve must be OFF before clearing data');
  }
  
  // Step 2: Clear Cache Reserve data
  const clearResponse = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${zoneId}/cache/cache_reserve_clear`,
    { method: 'POST', headers: { 'Authorization': `Bearer ${apiToken}` } }
  );
  return await clearResponse.json();
};

// Check clear status
const getClearStatus = async (zoneId: string, apiToken: string) => {
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${zoneId}/cache/cache_reserve_clear`,
    { method: 'GET', headers: { 'Authorization': `Bearer ${apiToken}` } }
  );
  return await response.json();
  // Returns: { state: "In-progress" | "Completed", start_ts: "..." }
};
```

**Clear process:**
1. Disable Cache Reserve (`value: 'off'`)
2. Call cache_reserve_clear endpoint
3. Deletion takes up to 24 hours
4. Re-enable Cache Reserve when ready

## Monitoring and Analytics

```typescript
// Dashboard: egress savings, requests served (hits/misses), storage, operations (A/B)
// Logpush field: CacheReserveUsed (boolean) - filter for Cache Reserve hits

// Query Cache Reserve hits
const query = `
  SELECT ClientRequestHost, COUNT(*) as requests, SUM(EdgeResponseBytes) as bytes
  FROM http_requests WHERE CacheReserveUsed = true
  GROUP BY ClientRequestHost ORDER BY requests DESC
`;
```

## Pricing

```typescript
// Storage: $0.015/GB-month | Class A (writes): $4.50/M | Class B (reads): $0.36/M
// Cache miss: 1A + 1B | Cache hit: 1B | Assets >1GB: proportionally more ops
```

## See Also

- [README](./README.md) - Overview and core concepts
- [Configuration](./configuration.md) - Setup and Cache Rules
- [Patterns](./patterns.md) - Best practices and optimization
- [Gotchas](./gotchas.md) - Common issues and troubleshooting
