SPB Git forge

spb/fetcha

Public
11commits 1branches 0releases
1.5 MBsize
maindefault branch
16 days agolast push
TypeScript 97.5% SQL 1.4% Python 0.8%
2.4 KB · 69 lines typescript
Raw Blame History
1import type { ConcreteNetwork, GeoTarget } from "@fetcha/core";2import { executeHttp } from "./http";3import type { ProviderHealth, ProviderRequest, ProviderResponse, ProxyProvider } from "./types";45/**6 * Direct egress from Fetcha's own infrastructure — no upstream proxy. Cheapest possible7 * route ("datacenter" class), no geo control. Used as the first attempt in `auto` mode only8 * when the domain profile says the site tolerates it, and only when enabled via9 * `FETCHA_DIRECT_EGRESS=1`. Disabled by default to keep the platform's own IPs clean.10 */11export class DirectProvider implements ProxyProvider {12  readonly id = "direct" as const;13  readonly label = "Fetcha direct egress";14  readonly networks: ConcreteNetwork[] = ["datacenter"];15  private readonly enabled: boolean;1617  constructor(env: NodeJS.ProcessEnv = process.env) {18    this.enabled = env.FETCHA_DIRECT_EGRESS === "1";19  }2021  isConfigured(): boolean {22    return this.enabled;23  }2425  supportsGeo(geo: GeoTarget): boolean {26    return !geo.country; // cannot target geography27  }2829  pricePerGb(): number {30    return 0.05;31  }3233  estimateCost(_network: ConcreteNetwork, bytes: number): number {34    return (bytes / 1_073_741_824) * this.pricePerGb();35  }3637  proxyEndpoint(): null {38    return null;39  }4041  async fetch(request: ProviderRequest): Promise<ProviderResponse> {42    return executeHttp(this.id, null, request);43  }4445  async health(network: ConcreteNetwork = "datacenter"): Promise<ProviderHealth> {46    if (!this.enabled) return { provider: this.id, network, status: "unconfigured", latencyMs: null, checkedAt: new Date(), detail: "Direct egress disabled" };47    const t0 = performance.now();48    try {49      const res = await this.fetch({50        requestId: "probe",51        attemptId: "probe",52        url: "https://www.cloudflare.com/cdn-cgi/trace",53        method: "GET",54        headers: {},55        timeoutMs: 8000,56        network,57        geo: { country: null, region: null, city: null },58        followRedirects: true,59        maxRedirects: 3,60        maxResponseBytes: 65536,61      });62      const latencyMs = Math.round(performance.now() - t0);63      return { provider: this.id, network, status: res.status < 500 ? "healthy" : "degraded", latencyMs, checkedAt: new Date() };64    } catch (e) {65      return { provider: this.id, network, status: "down", latencyMs: null, checkedAt: new Date(), detail: (e as Error).message };66    }67  }68}69