For replays and match metadata, always try R2 first and fall back to B2:
+For replays and match metadata, fetch directly from B2:
async function fetchReplay(matchId: string): Promise {
- // Try R2 warm cache first
- const r2Url = \`/r2/replays/\${matchId}.json.gz\`;
- const r2Resp = await fetch(r2Url);
- if (r2Resp.ok) {
- return decompress(await r2Resp.arrayBuffer());
- }
-
- // Fall back to B2 cold archive
const b2Url = \`https://b2.aicodebattle.com/replays/\${matchId}.json.gz\`;
const b2Resp = await fetch(b2Url);
if (!b2Resp.ok) throw new Error(\`Replay not found: \${matchId}\`);
@@ -565,9 +556,8 @@ export function renderDocsApiPage(): void {
Cache Behavior
- Pages: ~90 min stale max (deploy cycle)
- - R2 replays: immutable, cache forever
- - R2 live.json: 10 second max-age
- - B2: immutable, cache forever
+ - B2 replays: immutable, cache forever
+ - B2 live.json: 10 second max-age
Rate Limits
@@ -772,8 +762,7 @@ function renderSection(section: Section): string {
function renderEndpoint(endpoint: EndpointDoc, sectionTitle: string): string {
let baseUrl = '';
- if (sectionTitle.includes('R2')) baseUrl = R2_BASE;
- else if (sectionTitle.includes('B2')) baseUrl = B2_BASE;
+ if (sectionTitle.includes('B2')) baseUrl = B2_BASE;
else baseUrl = PAGES_BASE;
return `
diff --git a/web/src/pages/docs-data.ts b/web/src/pages/docs-data.ts
index 4869c59..04e2da9 100644
--- a/web/src/pages/docs-data.ts
+++ b/web/src/pages/docs-data.ts
@@ -15,8 +15,8 @@ export function renderDocsDataPage(): void {
All platform data is available as static JSON files served from Cloudflare Pages (indexes) and Cloudflare R2 (replays, metadata). No authentication, no API keys, no rate limiting.
Base URLs:
const PAGES = '' // Same origin (Cloudflare Pages)
-const R2 = 'https://r2.aicodebattle.com' // Warm replay cache
-const B2 = 'https://b2.aicodebattle.com' // Cold archive
+const B2 = 'https://b2.aicodebattle.com' // Warm replay cache
+const B2 = 'https://b2.aicodebattle.com' // Warm replay cache
Uploaded in real-time by match workers. R2 is a warm cache for recent replays; B2 is the permanent cold archive.
+Uploaded in real-time by match workers. B2 is a warm cache for recent replays; R2 is the permanent cold archive.
GET /replays/{match_id}.json.gz
Gzipped replay JSON. Browser handles decompression automatically.
-# Fetch from R2 (warm cache)
-curl https://r2.aicodebattle.com/replays/m_7f3a9b2c.json.gz
+ # Fetch from B2 (warm cache)
+curl https://b2.aicodebattle.com/replays/m_7f3a9b2c.json.gz
-# Fallback to B2 (cold archive)
+# Fallback to R2 (cold archive)
curl https://b2.aicodebattle.com/replays/m_7f3a9b2c.json.gz
Match Metadata
@@ -107,17 +107,17 @@ GET /cards/{bot_id}.png
Pages (indexes): Deployed every ~90 minutes. Cached by Cloudflare CDN globally. Invalidated on deploy.
-R2 (replays): Served with Cache-Control: immutable, max-age=31536000 (content-addressed, never changes).
B2 (archive): Same cache headers as R2. Free egress via Cloudflare Bandwidth Alliance.
+B2 (replays): Served with Cache-Control: immutable, max-age=31536000 (content-addressed, never changes).
R2 (archive): Same cache headers as B2.
// SPA shell + index data from Pages (same origin)
const leaderboard = await fetch('/data/leaderboard.json').then(r => r.json())
-// Replay from R2 warm cache, with B2 fallback
+// Replay from B2 warm cache, with R2 fallback
async function fetchReplay(matchId) {
- const r2 = await fetch(\`https://r2.aicodebattle.com/replays/\${matchId}.json.gz\`)
- if (r2.ok) return r2
+ const b2 = await fetch(\`https://b2.aicodebattle.com/replays/\${matchId}.json.gz\`)
+ if (b2.ok) return b2
return fetch(\`https://b2.aicodebattle.com/replays/\${matchId}.json.gz\`)
}
Replays are served from Cloudflare R2 (warm cache) with B2 (cold archive) fallback:
+Replays are served from Backblaze B2 (warm cache) with R2 (cold archive) fallback:
# Try warm cache first
-curl https://r2.aicodebattle.com/replays/\${match_id}.json.gz
+curl https://b2.aicodebattle.com/replays/\${match_id}.json.gz
# Fallback to cold archive
curl https://b2.aicodebattle.com/replays/\${match_id}.json.gz
diff --git a/web/test-match-list.js b/web/test-match-list.js
index 9ff2664..2ee0982 100644
--- a/web/test-match-list.js
+++ b/web/test-match-list.js
@@ -169,8 +169,8 @@ async function main() {
// Check if replay file exists
const replayPath = path.join(publicDir, 'replays', `${firstMatch.id}.json.gz`);
- // Note: Replays are on R2, not in public folder, so we just check the format
- logInfo(`Replay files served from R2: https://r2.aicodebattle.com${expectedUrl}`);
+ // Note: Replays are on B2, not in public folder, so we just check the format
+ logInfo(`Replay files served from B2: https://b2.aicodebattle.com${expectedUrl}`);
warned++;
}
@@ -218,10 +218,10 @@ async function main() {
failed++;
}
- // Test 5: Check thumbnails (R2)
+ // Test 5: Check thumbnails (B2)
logInfo('\nTest 5: Checking thumbnail availability...');
- logInfo('Thumbnails served from R2: https://r2.aicodebattle.com/thumbnails/{match_id}.png');
- logWarn('R2 thumbnail upload is broken (ESO credentials issue - known issue)');
+ logInfo('Thumbnails served from B2: https://b2.aicodebattle.com/thumbnails/{match_id}.png');
+ logWarn('B2 thumbnail upload is broken (ESO credentials issue - known issue)');
logWarn('Thumbnails will 404 or show placeholders - UI should handle gracefully');
warned++;