From 5fb36dcc9411493538bd8cb2aab30076cc57d17f Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Sat, 17 Oct 2026 17:28:05 +0200 Subject: [PATCH] fix(stats): use a supported Workers redirect mode --- stats/src/fleet.ts | 2 +- stats/src/usage.ts | 2 +- stats/test/worker.test.ts | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/stats/src/fleet.ts b/stats/src/fleet.ts index 8c5e4ea..11b00ce 100644 --- a/stats/src/fleet.ts +++ b/stats/src/fleet.ts @@ -27,7 +27,7 @@ export function parseFleet(value: unknown, nowMs: number): PublicFleetFeed { export async function collectFleet(env: AppEnv, nowMs = Date.now()) { const started = new Date(nowMs).toISOString() try { - const r=await fetch('https://cloud.ftw.energy/v1/fleet/public',{redirect:'error',headers:{accept:'application/json'},signal:AbortSignal.timeout(15000)}) + const r=await fetch('https://cloud.ftw.energy/v1/fleet/public',{redirect:'manual',headers:{accept:'application/json'},signal:AbortSignal.timeout(15000)}) if (!r.ok) {await r.body?.cancel();throw new Error('fleet unavailable')} const reader=r.body?.getReader(); if (!reader) throw new Error('empty fleet') const parts:Uint8Array[]=[];let size=0 diff --git a/stats/src/usage.ts b/stats/src/usage.ts index 7a868b9..d4612d1 100644 --- a/stats/src/usage.ts +++ b/stats/src/usage.ts @@ -40,7 +40,7 @@ export function parseUsage(value: unknown, nowMs: number): UsageView { export async function collectUsage(env: AppEnv, nowMs = Date.now()): Promise { const started = new Date(nowMs).toISOString() try { - const response = await fetch('https://cloud.ftw.energy/v1/stats', { headers: { accept: 'application/json' }, redirect: 'error', signal: AbortSignal.timeout(15_000) }) + const response = await fetch('https://cloud.ftw.energy/v1/stats', { headers: { accept: 'application/json' }, redirect: 'manual', signal: AbortSignal.timeout(15_000) }) if (response.status === 503 && response.headers.get('FTW-Statistics-State') === 'disabled') {await response.body?.cancel(); await saveCollectorRun(env.DB,'cloud:usage',started,true,'awaiting policy approval');return} if (!response.ok) { await response.body?.cancel(); throw new Error('usage source unavailable') } const reader = response.body?.getReader() diff --git a/stats/test/worker.test.ts b/stats/test/worker.test.ts index 03e559f..48f790a 100644 --- a/stats/test/worker.test.ts +++ b/stats/test/worker.test.ts @@ -779,3 +779,22 @@ describe('installation estimates',()=>{ await expect(collectUsage(env,now)).resolves.toBeUndefined() }) }) + + +describe('Cloud collector redirects in the Workers runtime', () => { + it.each([['usage', collectUsage], ['fleet', collectFleet]] as const)( + '%s uses a valid edge Request and rejects a redirect without storing it', + async (_name, collect) => { + const send = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { + const request = new Request(input, init) + expect(request.redirect).toBe('manual') + return new Response(null, {status: 302, headers: {location: 'https://other.example/feed'}}) + }) + vi.stubGlobal('fetch', send) + await expect(collect(env)).rejects.toThrow('unavailable') + expect(send).toHaveBeenCalledTimes(1) + expect(await env.DB.prepare('SELECT COUNT(*) AS n FROM usage_snapshots').first('n')).toBe(0) + expect(await env.DB.prepare('SELECT COUNT(*) AS n FROM cloud_fleet_view').first('n')).toBe(0) + } + ) +})