Network Stack: wrapped fetch() + NetworkLog + cookie integration #4

Closed
opened 2026-06-17 13:37:43 +00:00 by Artur · 1 comment
Owner

Goal

Implement a wrapped fetch() that:

  • Uses Bun.fetch under the hood
  • Attaches cookies from CookieJar
  • Stores Set-Cookie responses back in CookieJar
  • Logs all requests/responses to NetworkLog
  • Handles redirects, CORS-ish headers, keepalive, abort, compression

What to Build

src/network/fetch.ts

export interface FetchOptions {
  // Extended options beyond standard fetch
}

export function createFetch(cookieJar: CookieJar, networkLog: NetworkLog): typeof fetch {
  // Wraps the global fetch:
  // 1. Normalize RequestInfo/RequestInit to a Request object
  // 2. Attach cookies from CookieJar.match(url)
  // 3. Log request to NetworkLog
  // 4. Call Bun.fetch
  // 5. Store Set-Cookie headers in CookieJar
  // 6. Log response to NetworkLog
  // 7. Return Response object
}

src/network/log.ts

export interface NetworkLogEntry {
  type: 'request' | 'response' | 'xhr' | 'websocket';
  url: string;
  method?: string;
  status?: number;
  requestHeaders?: Record<string, string>;
  responseHeaders?: Record<string, string>;
  bodySize?: number;
  timing: { start: number; end: number };
  error?: string;
}

export class NetworkLog {
  private entries: NetworkLogEntry[] = [];

  log(entry: Omit<NetworkLogEntry, 'timing'>): void;
  getEntries(): readonly NetworkLogEntry[];
  clear(): void;
  dump(): NetworkLogEntry[];
}

Required fetch features

Feature Implementation
Cookies Attach Cookie header, store Set-Cookie
Redirects Follow (default), manual, error
Referrer/Origin Pass through from request init
Credentials include, same-origin, omit
CORS-ish Add Origin header, check ACAO
Headers Normalization, set, get, entries
Compression gzip, brotli, deflate (Bun handles)
Streaming ReadableStream response body
AbortController signal/abort support
Keepalive fetch after page unload
Cache modes default, no-store, reload, no-cache, force-cache (faked)

Tests

Unit Tests

Test Verifies
fetch.basic.test.ts fetch() returns Response with status, headers, body
fetch.cookies.test.ts Cookies attached from jar, Set-Cookie stored
fetch.logging.test.ts Requests logged to NetworkLog
fetch.redirect.test.ts Redirects followed, final URL in log
fetch.abort.test.ts AbortController works, logs error
fetch.headers.test.ts Request headers preserved, normalized
network-log.test.ts NetworkLog records entries, clear(), dump()
network-log.timing.test.ts Timing captured correctly

Integration Tests

Test Verifies
fetch.integration.test.ts fetch -> cookie -> fetch verifies cookie round-trip

Definition of Done

  • src/network/fetch.ts implemented with createFetch()
  • src/network/log.ts implemented with NetworkLog
  • Cookie jar integration (attach + store)
  • AbortController support
  • Redirect handling
  • All tests pass
  • 100% line + branch coverage
## Goal Implement a wrapped fetch() that: - Uses Bun.fetch under the hood - Attaches cookies from CookieJar - Stores Set-Cookie responses back in CookieJar - Logs all requests/responses to NetworkLog - Handles redirects, CORS-ish headers, keepalive, abort, compression ## What to Build ### src/network/fetch.ts ``` export interface FetchOptions { // Extended options beyond standard fetch } export function createFetch(cookieJar: CookieJar, networkLog: NetworkLog): typeof fetch { // Wraps the global fetch: // 1. Normalize RequestInfo/RequestInit to a Request object // 2. Attach cookies from CookieJar.match(url) // 3. Log request to NetworkLog // 4. Call Bun.fetch // 5. Store Set-Cookie headers in CookieJar // 6. Log response to NetworkLog // 7. Return Response object } ``` ### src/network/log.ts ``` export interface NetworkLogEntry { type: 'request' | 'response' | 'xhr' | 'websocket'; url: string; method?: string; status?: number; requestHeaders?: Record<string, string>; responseHeaders?: Record<string, string>; bodySize?: number; timing: { start: number; end: number }; error?: string; } export class NetworkLog { private entries: NetworkLogEntry[] = []; log(entry: Omit<NetworkLogEntry, 'timing'>): void; getEntries(): readonly NetworkLogEntry[]; clear(): void; dump(): NetworkLogEntry[]; } ``` ### Required fetch features | Feature | Implementation | |---------|---------------| | Cookies | Attach Cookie header, store Set-Cookie | | Redirects | Follow (default), manual, error | | Referrer/Origin | Pass through from request init | | Credentials | include, same-origin, omit | | CORS-ish | Add Origin header, check ACAO | | Headers | Normalization, set, get, entries | | Compression | gzip, brotli, deflate (Bun handles) | | Streaming | ReadableStream response body | | AbortController | signal/abort support | | Keepalive | fetch after page unload | | Cache modes | default, no-store, reload, no-cache, force-cache (faked) | ## Tests ### Unit Tests | Test | Verifies | |------|----------| | fetch.basic.test.ts | fetch() returns Response with status, headers, body | | fetch.cookies.test.ts | Cookies attached from jar, Set-Cookie stored | | fetch.logging.test.ts | Requests logged to NetworkLog | | fetch.redirect.test.ts | Redirects followed, final URL in log | | fetch.abort.test.ts | AbortController works, logs error | | fetch.headers.test.ts | Request headers preserved, normalized | | network-log.test.ts | NetworkLog records entries, clear(), dump() | | network-log.timing.test.ts | Timing captured correctly | ### Integration Tests | Test | Verifies | |------|----------| | fetch.integration.test.ts | fetch -> cookie -> fetch verifies cookie round-trip | ## Definition of Done - [ ] src/network/fetch.ts implemented with createFetch() - [ ] src/network/log.ts implemented with NetworkLog - [ ] Cookie jar integration (attach + store) - [ ] AbortController support - [ ] Redirect handling - [ ] All tests pass - [ ] 100% line + branch coverage
Author
Owner

Network Stack: wrapped fetch() + NetworkLog + cookie integration. Implementiert in src/network/fetch.ts + RequestManager. Tests: fetch.test.ts, fetch-headers-bot-detection.test.ts.

Network Stack: wrapped fetch() + NetworkLog + cookie integration. ✅ Implementiert in src/network/fetch.ts + RequestManager. Tests: fetch.test.ts, fetch-headers-bot-detection.test.ts.
Artur closed this issue 2026-06-18 06:28:02 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
glow-all/true-headless-browser#4
No description provided.